Initial checkin of GazeControls code

This commit is contained in:
Harish S. Kulkarni 2021-08-02 21:31:34 -07:00
Родитель 5197f59290
Коммит 62ce25c925
36 изменённых файлов: 3836 добавлений и 0 удалений

234
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,234 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.filters
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
## TODO: Comment the next line if you want to checkin your
## web deploy settings but do note that will include unencrypted
## passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
BundleArtifacts
!/build
/build/tools/GitVersion.CommandLine
AppPackages
# NuGet V3 artifacts
*-packages.config
*.nuget.props
*.nuget.targets
project.lock.json
msbuild.binlog
*.project.lock.json
/build/tools/**
!/build/tools/packages.config
# Generated file from .ttinclude
**/Generated/TypeInfo.g.cs
# TAEF Log output
WexLogFileOutput
*.wtl

Просмотреть файл

@ -0,0 +1,34 @@
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>uap10.0.17763</TargetFrameworks>
<Title>Windows Community Toolkit Gaze Controls Library</Title>
<Description>A library controls optimized for gaze interaction</Description>
<PackageTags>Windows;Community;Toolkit;WCT;UWP;Gaze;Eye;Tracker;EyeTracker</PackageTags>
</PropertyGroup>
<ItemGroup>
<Content Include="KeyboardLayouts\FilenameEntry.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="KeyboardLayouts\FullKeyboard.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="KeyboardLayouts\MinAAC.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="KeyboardLayouts\TwoStageKeyboard.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Toolkit.Uwp.Input.GazeInteraction" Version="7.0.2" />
<PackageReference Include="Microsoft.Toolkit.Uwp.UI" Version="7.0.2" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Strings\en-us\Resources.resw" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using Windows.Storage;
using Windows.UI.Xaml;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
/// <summary>
/// Gaze optimized file picker to open files
/// </summary>
public sealed class GazeFileOpenPicker : GazeFilePicker
{
/// <summary>
/// Initializes a new instance of the <see cref="GazeFileOpenPicker"/> class.
/// </summary>
public GazeFileOpenPicker()
{
Title = GetString("FileOpen/Title");
this.FilePickerInitialized += OnGazeFileOpenPickerInitialized;
}
private void OnGazeFileOpenPickerInitialized(object sender, EventArgs e)
{
SelectButton = Button2;
SelectButton.Click += OnOpenButtonClicked;
SelectButton.Content = GetString("Open");
Button3.Click += OnCancelClicked;
Button3.Content = GetString("Cancel");
}
private void OnCancelClicked(object sender, RoutedEventArgs e)
{
Hide();
}
private void OnOpenButtonClicked(object sender, RoutedEventArgs args)
{
Debug.Assert(!CurrentSelectedItem.IsFolder, "Selected item should not be a folder!");
SelectedItem = CurrentSelectedItem?.Item as StorageFile;
Hide();
}
}
}

Просмотреть файл

@ -0,0 +1,162 @@
<ContentDialog
x:Class="CommunityToolkit.Labs.Uwp.GazeControls.GazeFilePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
MinWidth="1000"
Width="1500" Height="800"
FullSizeDesired="True"
>
<ContentDialog.Resources>
<DataTemplate x:Key="FolderItemTemplate" x:DataType="local:StorageItem">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="8*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Width="128" Height="128" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Source="{x:Bind Thumbnail}" />
<TextBlock Grid.Row="1" HorizontalAlignment="Stretch" Text="{x:Bind Name}" HorizontalTextAlignment="Center" />
</Grid>
</DataTemplate>
<Style x:Key="CommandSpaceButtonStyles" TargetType="Button">
<Setter Property="Height" Value="120" />
<Setter Property="Width" Value="240" />
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
<Style x:Key="PickerButtonStyles" TargetType="Button">
<Setter Property="Height" Value="120" />
<Setter Property="Width" Value="120" />
<Setter Property="Margin" Value="0,0,16,8" />
</Style>
<x:Double x:Key="ContentDialogMaxWidth">9999</x:Double>
<x:Double x:Key="ContentDialogMaxHeight">9999</x:Double>
<Style TargetType="local:GazeFilePicker" BasedOn="{StaticResource DefaultContentDialogStyle}" />
</ContentDialog.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="140"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" x:Name="FilenameEntryGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox x:Name="FilenameEditBox" Grid.Row="0" TextWrapping="Wrap" FontSize="45" Margin="3,3,0,3" AcceptsReturn="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<local:GazeKeyboard x:Name="GazeKeyboard" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
<UserControl Grid.Row="0" x:Name="FileListingGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="130" />
<RowDefinition Height="*" />
<RowDefinition Height="130" />
</Grid.RowDefinitions>
<StackPanel x:Name="FavoritesPanel" Grid.Row="0" Orientation="Horizontal">
</StackPanel>
<Border Grid.Row="1" BorderBrush="Black" BorderThickness="1" Margin="0,0,0,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="140"/>
</Grid.ColumnDefinitions>
<local:ScrollGridView Grid.Row="0" Grid.Column="0" x:Name="CurrentFolderContents"
IsItemClickEnabled="True"
SelectionMode="Single"
ItemTemplate="{StaticResource FolderItemTemplate}"
ItemsSource="{x:Bind Mode=OneWay, Path=CurrentFolderItems}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
ItemClick="OnCurrentFolderContentsItemClick"
MinWidth="1500"
/>
<local:GazeScrollBar Grid.Row="0" Grid.Column="1" x:Name="CurrentFolderScrollbar" Orientation="Vertical" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</Border>
<Grid Grid.Row="2" Margin="0,10,0,0" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="144"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="ParentFolderButton" Grid.Column="0" Grid.RowSpan="2" Width="120" Height="120" Click="OnParentFolderClick" Content="&#xF0AD;" FontFamily="Segoe MDL2 Assets" FontSize="32" Margin="0,0,20,0"/>
<Border Grid.Row="0" Grid.Column="1" BorderThickness="1" BorderBrush="Black" HorizontalAlignment="Stretch" Margin="0,0,0,8">
<ScrollViewer x:Name="SelectedItemScrollViewer" VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Hidden" VerticalScrollMode="Disabled"
HorizontalScrollMode="Enabled" >
<TextBlock Text="{x:Bind Mode=OneWay, Path=CurrentSelectedItem.Path}"
FontWeight="Bold" FontSize="18" Margin="16,0,0,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch" Padding="0,0,16,0"/>
</ScrollViewer>
</Border>
<Border Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="Black" Margin="0,8,0,0">
<TextBlock x:Name="FileTypeFilterTextBlock" FontSize="18"/>
</Border>
</Grid>
</Grid>
</UserControl>
<Border Grid.Row="0" x:Name="FileOverwriteConfirmationGrid"
BorderThickness="2" BorderBrush="Black" HorizontalAlignment="Center"
VerticalAlignment="Center" Visibility="Collapsed" Background="White">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="120"/>
<RowDefinition Height="120"/>
<RowDefinition Height="180"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Background="Blue" >
<TextBlock Text="Confirm overwrite" HorizontalAlignment="Left" FontSize="32" Foreground="White" Padding="5,0,0,0"/>
</Border>
<Border Grid.Row="1" Grid.Column="0" Grid.RowSpan="2" Background="White" >
<TextBlock Text="&#xE7BA;" FontSize="64" FontFamily="Segoe MDL2 Assets" Foreground="Yellow" VerticalAlignment="Center"/>
</Border>
<TextBlock Grid.Row="1" Grid.Column="1" x:Name="OverwriteWarning" FontSize="32" VerticalAlignment="Bottom" Margin="0,0,20,0" />
<TextBlock Grid.Row="2" Grid.Column="1" Text="Do you want to replace it?" FontSize="32" VerticalAlignment="Top" Margin="0,0,20,0" />
<Grid Grid.Row="3" Grid.ColumnSpan="2" Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" x:Name="YesBtn" Content="Yes" HorizontalAlignment="Center" Style="{StaticResource CommandSpaceButtonStyles}" Margin="10,0,10,0"/>
<Button Grid.Row="0" Grid.Column="1" x:Name="NoBtn" Content="No" HorizontalAlignment="Center" Style="{StaticResource CommandSpaceButtonStyles}" Margin="10,0,10,0"/>
</Grid>
</Grid>
</Border>
<UserControl Grid.Row="1" x:Name="CommandRow" VerticalAlignment="Bottom">
<Grid VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="Col0Button" Style="{StaticResource CommandSpaceButtonStyles}" Visibility="Collapsed"/>
<Button Grid.Column="1" x:Name="Col1Button" Style="{StaticResource CommandSpaceButtonStyles}" Visibility="Collapsed"/>
<Button Grid.Column="2" x:Name="Col2Button" Style="{StaticResource CommandSpaceButtonStyles}" />
<Button Grid.Column="3" x:Name="Col3Button" Style="{StaticResource CommandSpaceButtonStyles}" />
</Grid>
</UserControl>
</Grid>
</ContentDialog>

Просмотреть файл

@ -0,0 +1,382 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp.Input.GazeInteraction;
using Microsoft.Toolkit.Uwp.UI;
using Windows.ApplicationModel.Resources;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
internal enum FilePickerView
{
FileListing,
FilenameEntry,
FileOverwriteConfirmation
}
/// <summary>
/// Provides file picker dialogs optimized for gaze input
/// </summary>
public abstract partial class GazeFilePicker : ContentDialog
{
private bool _dialogInitialized;
private bool _refreshNeeded;
private ResourceLoader _resourceLoader;
internal FilePickerView CurrentView { get; private set; }
internal Button SelectButton { get; set; }
/// <summary>
/// Gets or sets the event handler that is called when the file picker has fully initialized
/// </summary>
public EventHandler FilePickerInitialized { get; protected set; }
/// <summary>
/// Gets or sets the currently selected file in the dialog as a StorageFile
/// </summary>
public StorageFile SelectedItem { get; protected set; }
internal Button Button0 { get; private set; }
internal Button Button1 { get; private set; }
internal Button Button2 { get; private set; }
internal Button Button3 { get; private set; }
internal Button YesButton { get; private set; }
internal Button NoButton { get; private set; }
internal TextBox FilenameTextbox { get; private set; }
private StorageFolder _currentFolder;
internal static readonly DependencyProperty CurrentSelectedItemProperty =
DependencyProperty.Register(
"CurrentSelectedItem",
typeof(StorageItem),
typeof(GazeFilePicker),
null);
internal StorageItem CurrentSelectedItem
{
get { return (StorageItem)GetValue(CurrentSelectedItemProperty); }
set { SetValue(CurrentSelectedItemProperty, value); }
}
internal static readonly DependencyProperty CurrentFolderItemsProperty =
DependencyProperty.Register(
"CurrentFolderItems",
typeof(ObservableCollection<StorageItem>),
typeof(GazeFilePicker),
null);
internal ObservableCollection<StorageItem> CurrentFolderItems
{
get { return (ObservableCollection<StorageItem>)GetValue(CurrentFolderItemsProperty); }
set { SetValue(CurrentFolderItemsProperty, value); }
}
/// <summary>
/// Gets or sets the current folder for the file picker dialog
/// </summary>
public StorageFolder CurrentFolder
{
get
{
return _currentFolder;
}
set
{
RefreshContents(value);
}
}
/// <summary>
/// Gets or sets the list of storage folders that appear as shortcuts
/// on top of the folder view
/// </summary>
public List<StorageFolder> Favorites { get; set; }
/// <summary>
/// Gets or sets the collection of file types that the file open picker displays.
/// </summary>
public List<string> FileTypeFilter { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="GazeFilePicker"/> class.
/// </summary>
public GazeFilePicker()
{
this.InitializeComponent();
this.Loaded += this.OnGazeFilePickerLoaded;
FileTypeFilter = new List<string>();
var resourcePath = "CommunityToolkit.Labs.Uwp.GazeControls/Resources";
_resourceLoader = ResourceLoader.GetForViewIndependentUse(resourcePath);
}
private async void OnGazeFilePickerLoaded(object sender, RoutedEventArgs e)
{
Button0 = Col0Button;
Button1 = Col1Button;
Button2 = Col2Button;
Button3 = Col3Button;
YesButton = YesBtn;
NoButton = NoBtn;
FilenameTextbox = FilenameEditBox;
CurrentFolderContents.GazeScrollBar = CurrentFolderScrollbar;
GazeInput.SetMaxDwellRepeatCount(this, 2);
GazeKeyboard.Target = FilenameTextbox;
var uri = new Uri($"ms-appx:///CommunityToolkit.Labs.Uwp.GazeControls/KeyboardLayouts/FilenameEntry.xaml");
var layoutFile = await StorageFile.GetFileFromApplicationUriAsync(uri);
await GazeKeyboard.TryLoadLayoutAsync(layoutFile);
var dialogSpace = this.FindDescendant("DialogSpace") as Grid;
var commandSpace = this.FindDescendant("CommandSpace") as Grid;
dialogSpace.Children.Remove(commandSpace);
SetFilePickerView(FilePickerView.FileListing);
CreateFavoritesButtons();
SetFileTypeFilterText();
_dialogInitialized = true;
if (_refreshNeeded)
{
RefreshContents(_currentFolder);
}
if (FilePickerInitialized != null)
{
FilePickerInitialized(this, null);
}
}
/// <summary>
/// Returns the localized string from resources
/// </summary>
/// <param name="resource">Resource id of the string to get</param>
/// <returns>Localized string</returns>
protected string GetString(string resource)
{
return _resourceLoader.GetString(resource);
}
private void SetFileTypeFilterText()
{
var filters = FileTypeFilter.Select(item => Regex.Replace(item, "^\u002E", "*."));
var allFilters = string.Join(", ", filters);
FileTypeFilterTextBlock.Text = allFilters;
}
private async void CreateFavoritesButtons()
{
var favoritesPanel = this.FindDescendant("FavoritesPanel") as StackPanel;
Debug.Assert(favoritesPanel != null, "KnownFoldersPanel not found");
var style = (Style)this.Resources["PickerButtonStyles"];
favoritesPanel.Children.Clear();
List<StorageFolder> favorites;
if ((Favorites == null) || (Favorites.Count == 0))
{
KnownFolderId[] knownFolderIds =
{
KnownFolderId.DocumentsLibrary,
KnownFolderId.PicturesLibrary,
KnownFolderId.VideosLibrary,
KnownFolderId.MusicLibrary
};
favorites = new List<StorageFolder>();
foreach (var folderId in knownFolderIds)
{
try
{
var knownFolder = await KnownFolders.GetFolderAsync(folderId);
favorites.Add(knownFolder);
}
catch (Exception)
{
continue;
}
}
}
else
{
favorites = Favorites;
}
foreach (var folder in favorites)
{
var button = new Button();
button.Style = style;
button.Tag = folder;
button.Click += OnFavoritesClick;
button.Content = folder.Name;
favoritesPanel.Children.Add(button);
}
}
/// <summary>
/// Helper to create a folder in _currentFolder
/// </summary>
/// <returns>Task</returns>
protected async Task CreateFolderAsync()
{
await _currentFolder.CreateFolderAsync(FilenameTextbox.Text);
RefreshContents(_currentFolder);
}
/// <summary>
/// Helper to create a file in the current folder
/// </summary>
/// <returns>IAsyncOperation[StorageFile]</returns>
protected IAsyncOperation<StorageFile> CreateFileAsync(bool fromTextbox)
{
var filename = fromTextbox ? FilenameTextbox.Text : CurrentSelectedItem.Name;
return _currentFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
}
/// <summary>
/// Helper function to set the overwrite warning text
/// </summary>
protected void SetOverwriteWarningText()
{
var warningTextFormat = GetString("OverwriteWarning");
OverwriteWarning.Text = string.Format(warningTextFormat, CurrentSelectedItem.Name);
}
internal void SetFilePickerView(FilePickerView filePickerView)
{
FrameworkElement[] viewGrids = { FileListingGrid, FilenameEntryGrid, FileOverwriteConfirmationGrid };
foreach (var grid in viewGrids)
{
grid.Visibility = Visibility.Collapsed;
}
viewGrids[(int)filePickerView].Visibility = Visibility.Visible;
CurrentView = filePickerView;
if (CurrentView == FilePickerView.FileOverwriteConfirmation)
{
FileListingGrid.Visibility = Visibility.Visible;
FileListingGrid.IsEnabled = false;
CommandRow.IsEnabled = false;
}
else if (CurrentView == FilePickerView.FileListing)
{
FileListingGrid.IsEnabled = true;
CommandRow.IsEnabled = true;
}
FixFileListingButtons();
}
private async void FixFileListingButtons()
{
var folder = await _currentFolder.GetParentAsync();
ParentFolderButton.IsEnabled = folder != null;
SelectButton.IsEnabled = (CurrentSelectedItem != null) && (!CurrentSelectedItem.IsFolder);
}
private Task[] GetThumbnailsAsync(ObservableCollection<StorageItem> storageItems)
{
Task[] tasks = new Task[storageItems.Count];
for (int i = 0; i < storageItems.Count; i++)
{
tasks[i] = storageItems[i].GetThumbnailAsync();
}
return tasks;
}
private async void RefreshContents(StorageFolder folder)
{
if (folder == null)
{
return;
}
_currentFolder = folder;
if (!_dialogInitialized)
{
_refreshNeeded = true;
return;
}
_refreshNeeded = false;
var allItems = await folder.GetItemsAsync();
var items = allItems.Where(item => item.IsOfType(StorageItemTypes.Folder) ||
FileTypeFilter.Contains((item as StorageFile).FileType));
var currentFolderItems = new ObservableCollection<StorageItem>(items.Select(item => new StorageItem(item)));
var tasks = GetThumbnailsAsync(currentFolderItems);
await Task.WhenAll(tasks);
SelectedItemScrollViewer.ChangeView(SelectedItemScrollViewer.ExtentWidth, 0.0, 1.0f);
CurrentSelectedItem = new StorageItem(_currentFolder);
CurrentFolderItems = currentFolderItems;
FixFileListingButtons();
}
private void OnCurrentFolderContentsItemClick(object sender, ItemClickEventArgs e)
{
var clickedItem = e.ClickedItem as StorageItem;
var selectedItem = CurrentFolderContents.SelectedItem as StorageItem;
if (clickedItem.IsFolder)
{
RefreshContents(clickedItem.Item as StorageFolder);
SelectButton.IsEnabled = false;
}
else
{
SelectButton.IsEnabled = true;
}
CurrentSelectedItem = clickedItem;
}
private async void OnParentFolderClick(object sender, RoutedEventArgs e)
{
var folder = await _currentFolder.GetParentAsync();
RefreshContents(folder);
}
private void OnFavoritesClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
var folder = button.Tag as StorageFolder;
RefreshContents(folder);
}
}
}

Просмотреть файл

@ -0,0 +1,123 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
/// <summary>
/// This class provides a file-save picker dialog for UWP apps that is optimized for gaze input
/// </summary>
public sealed class GazeFileSavePicker : GazeFilePicker
{
private bool _newFolderMode;
private Button _newFolderButton;
private Button _enterFilenameButton;
/// <summary>
/// Initializes a new instance of the <see cref="GazeFileSavePicker"/> class.
/// </summary>
public GazeFileSavePicker()
{
Title = GetString("FileSave/Title");
FilePickerInitialized += OnGazeFileSavePickerInitialized;
}
private void ShowCommandspaceButtons(bool show)
{
var visibility = show ? Visibility.Visible : Visibility.Collapsed;
_newFolderButton.Visibility = visibility;
_enterFilenameButton.Visibility = visibility;
_newFolderButton.Content = GetString("NewFolder");
_enterFilenameButton.Content = GetString("EnterFilename");
SelectButton.Content = GetString("Save");
Button3.Content = GetString("Cancel");
}
private void OnEnterFilenameClicked(object sender, RoutedEventArgs e)
{
FilenameTextbox.Text = string.Empty;
FilenameTextbox.TextChanged += OnFilenameChanged;
ShowCommandspaceButtons(false);
SetFilePickerView(FilePickerView.FilenameEntry);
}
private void OnFilenameChanged(object sender, TextChangedEventArgs e)
{
SelectButton.IsEnabled = FilenameTextbox.Text.Length > 0;
}
private void OnNewFolderClicked(object sender, RoutedEventArgs e)
{
_newFolderMode = true;
FilenameTextbox.Text = string.Empty;
FilenameTextbox.TextChanged += OnFilenameChanged;
ShowCommandspaceButtons(false);
SetFilePickerView(FilePickerView.FilenameEntry);
}
private void OnGazeFileSavePickerInitialized(object sender, EventArgs e)
{
_newFolderButton = Button0;
_newFolderButton.Click += OnNewFolderClicked;
_enterFilenameButton = Button1;
_enterFilenameButton.Click += OnEnterFilenameClicked;
SelectButton = Button2;
SelectButton.Click += OnSaveButtonClicked;
Button3.Click += OnCloseButtonClicked;
YesButton.Click += OnSaveButtonClicked;
NoButton.Click += OnCloseButtonClicked;
ShowCommandspaceButtons(true);
}
private async void OnSaveButtonClicked(object sender, RoutedEventArgs e)
{
if (_newFolderMode)
{
_newFolderMode = false;
await CreateFolderAsync();
SetFilePickerView(FilePickerView.FileListing);
ShowCommandspaceButtons(true);
}
else if (CurrentView == FilePickerView.FilenameEntry)
{
SelectedItem = await CreateFileAsync(true);
Hide();
}
else if (CurrentView == FilePickerView.FileListing)
{
SetOverwriteWarningText();
SetFilePickerView(FilePickerView.FileOverwriteConfirmation);
}
else
{
SelectedItem = await CreateFileAsync(false);
Hide();
}
FilenameTextbox.TextChanged -= OnFilenameChanged;
}
private void OnCloseButtonClicked(object sender, RoutedEventArgs e)
{
if (CurrentView == FilePickerView.FileListing)
{
Hide();
}
else
{
SetFilePickerView(FilePickerView.FileListing);
ShowCommandspaceButtons(true);
}
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
<UserControl
x:Class="CommunityToolkit.Labs.Uwp.GazeControls.GazeKeyboard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
mc:Ignorable="d"
d:DesignHeight="600"
d:DesignWidth="800">
<Grid>
<Grid x:Name="DummyHiddenGrid" Visibility="Collapsed">
<Button local:GazeKeyboard.KeyType="Normal" local:GazeKeyboard.VK="1"/>
</Grid>
<Grid x:Name="LayoutRoot">
</Grid>
</Grid>
</UserControl>

Просмотреть файл

@ -0,0 +1,467 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp.UI;
using Windows.ApplicationModel.DataTransfer;
using Windows.Data.Text;
using Windows.Storage;
using Windows.System;
using Windows.UI.Input.Preview.Injection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Markup;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
/// <summary>
/// Gaze optimized soft keyboard with support for custom layouts and predictions
/// </summary>
public sealed partial class GazeKeyboard : UserControl
{
private InputInjector _injector;
private KeyboardPage _rootPage;
private TextPredictionGenerator _textPredictionGenerator;
private WordsSegmenter _wordsSegmenter;
private string _predictionLanguage;
private Button[] _predictionTargets;
/// <summary>
/// Gets or sets the target text box for injecting keys
/// </summary>
public TextBox Target { get; set; }
/// <summary>
/// Gets or sets the text prediction language
/// </summary>
public string PredictionLanguage
{
get
{
return _predictionLanguage;
}
set
{
_predictionLanguage = value;
_textPredictionGenerator = new TextPredictionGenerator(value);
_textPredictionGenerator.InputScope = Windows.UI.Text.Core.CoreTextInputScope.Text;
_wordsSegmenter = new WordsSegmenter(value);
}
}
/// <summary>
/// Gets or sets the prediction targets
/// </summary>
public Button[] PredictionTargets
{
get
{
return _predictionTargets;
}
set
{
if (_predictionTargets != null)
{
foreach (var target in _predictionTargets)
{
target.Click -= OnPredictionSelected;
}
}
_predictionTargets = value;
foreach (var target in _predictionTargets)
{
target.Click += OnPredictionSelected;
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="GazeKeyboard"/> class.
/// </summary>
public GazeKeyboard()
{
InitializeComponent();
PredictionLanguage = "en-US";
_injector = InputInjector.TryCreate();
}
private void BuildPageHierarchy(KeyboardPage parent)
{
var children = GazeKeyboard.GetPageList(parent.Page);
foreach (var childName in children)
{
var node = parent.Page.FindName(childName) as FrameworkElement;
if (node != null)
{
var childPage = new KeyboardPage(node, parent);
parent.ChildrenNames.Add(childName);
parent.Children.Add(childPage);
BuildPageHierarchy(childPage);
}
}
if (parent.Children.Count > 0)
{
parent.CurrentChild = parent.Children[0];
}
}
/// <summary>
/// Loads the given keyboard layout from a file
/// </summary>
/// <param name="layoutFile"> A XAML file that contains the layout of the keyboard</param>
/// <returns>Task</returns>
public async Task TryLoadLayoutAsync(StorageFile layoutFile)
{
try
{
var xaml = await FileIO.ReadTextAsync(layoutFile);
var xamlNode = XamlReader.Load(xaml) as FrameworkElement;
foreach (var button in xamlNode.FindDescendants().OfType<ButtonBase>())
{
button.Click += OnKeyboardButtonClick;
}
_rootPage = new KeyboardPage(xamlNode, null);
BuildPageHierarchy(_rootPage);
LayoutRoot.Children.Add(xamlNode);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
private bool HandleVirtualKey(int vk)
{
if (vk < 0)
{
return false;
}
var key = new InjectedInputKeyboardInfo();
key.VirtualKey = (ushort)vk;
_injector.InjectKeyboardInput(new[] { key });
UpdatePredictions();
return true;
}
private bool HandleVirtualKeyList(List<int> vkList)
{
var state = new Dictionary<int, bool>();
var keys = new List<InjectedInputKeyboardInfo>();
foreach (var vk in vkList)
{
var key = new InjectedInputKeyboardInfo();
key.VirtualKey = (ushort)vk;
if (state.ContainsKey(vk))
{
key.KeyOptions = InjectedInputKeyOptions.KeyUp;
state.Remove(vk);
}
else
{
state.Add(vk, true);
}
keys.Add(key);
}
_injector.InjectKeyboardInput(keys);
UpdatePredictions();
return true;
}
private bool HandleUnicodeChar(string unicode)
{
var curContent = Clipboard.GetContent();
Clipboard.Clear();
var dp = new DataPackage();
dp.SetText(unicode);
Clipboard.SetContent(dp);
var keyList = new List<int>();
keyList.Add((int)VirtualKey.Control);
keyList.Add((int)VirtualKey.V);
keyList.Add((int)VirtualKey.V);
keyList.Add((int)VirtualKey.Control);
return HandleVirtualKeyList(keyList);
}
private KeyboardPage FindContainer(KeyboardPage kbdPage, string containerName)
{
if (kbdPage.Page.Name == containerName)
{
return kbdPage;
}
KeyboardPage containerPage = null;
for (int i = 0; i < kbdPage.Children.Count; i++)
{
containerPage = FindContainer(kbdPage.Children[i], containerName);
if (containerPage != null)
{
return containerPage;
}
}
return null;
}
private void HandlePageChange(string containerName, ButtonBase sender)
{
var container = FindContainer(_rootPage, containerName);
var tempPage = GazeKeyboard.GetTemporaryPage(sender);
var newPage = GazeKeyboard.GetNewPage(sender);
string pageName;
pageName = (tempPage != null) ? tempPage : newPage;
// find the new page among its siblings
var children = container.Children;
for (int i = 0; i < children.Count; i++)
{
if (children[i].Page.Name == pageName)
{
// hide the current page
container.CurrentChild.Page.Visibility = Visibility.Collapsed;
container.Children[i].Page.Visibility = Visibility.Visible;
if (tempPage != null)
{
container.PrevChild = container.CurrentChild;
}
container.CurrentChild = container.Children[i];
}
}
}
private void RevertTempPage(ButtonBase button)
{
// This logic is based on the assumption that the button is placed in a grid or other container
// which is the parent page. This is the temp page that has to be reverted back. So we navigate
// to the grandparent of that page to identify the siblings of the parent page
var page = button.Parent as FrameworkElement;
if (page == null)
{
return;
}
var container = page.Parent as FrameworkElement;
if (container == null)
{
return;
}
var containerPage = FindContainer(_rootPage, container.Name);
if ((containerPage == null) || (containerPage.PrevChild == null))
{
return;
}
containerPage.CurrentChild.Page.Visibility = Visibility.Collapsed;
containerPage.PrevChild.Page.Visibility = Visibility.Visible;
containerPage.CurrentChild = containerPage.PrevChild;
containerPage.PrevChild = null;
}
private async void OnKeyboardButtonClick(object sender, RoutedEventArgs e)
{
var button = sender as ButtonBase;
Target.Focus(FocusState.Programmatic);
await Task.Delay(1);
string unicode;
string container;
int vk;
List<int> vkList;
bool injected = false;
if ((container = GazeKeyboard.GetPageContainer(button)) != null)
{
HandlePageChange(container, button);
}
else if ((vk = GazeKeyboard.GetVK(button)) != 0)
{
injected = HandleVirtualKey(vk);
}
else if (((vkList = GazeKeyboard.GetVKList(button)) != null) && (vkList.Count > 0))
{
injected = HandleVirtualKeyList(vkList);
}
else if ((unicode = GazeKeyboard.GetUnicode(button)) != null)
{
injected = HandleUnicodeChar(unicode);
}
else
{
var key = new InjectedInputKeyboardInfo();
key.ScanCode = button.Content.ToString()[0];
key.KeyOptions = InjectedInputKeyOptions.Unicode;
_injector.InjectKeyboardInput(new[] { key });
UpdatePredictions();
injected = true;
}
if (injected)
{
RevertTempPage(button);
}
}
private void InjectString(string str, bool addSpace)
{
if (addSpace)
{
str += " ";
}
var keys = new List<InjectedInputKeyboardInfo>();
foreach (var ch in str)
{
var key = new InjectedInputKeyboardInfo()
{
ScanCode = ch,
KeyOptions = InjectedInputKeyOptions.Unicode
};
keys.Add(key);
key = new InjectedInputKeyboardInfo()
{
ScanCode = ch,
KeyOptions = InjectedInputKeyOptions.Unicode | InjectedInputKeyOptions.KeyUp
};
keys.Add(key);
}
// Injecting too many keys at once can result in ArgumentException.
// So inject a max of 8 keys at a time. 8 seems to work for now.
for (int i = 0; i < keys.Count; )
{
var count = Math.Min(8, keys.Count - i);
_injector.InjectKeyboardInput(keys.GetRange(i, count));
i += count;
}
}
private void OnPredictionSelected(object sender, RoutedEventArgs e)
{
WordSegment replaceSegment = null;
if (Target.SelectionStart < Target.Text.Length)
{
replaceSegment = _wordsSegmenter.GetTokenAt(Target.Text, (uint)Target.SelectionStart);
}
else if (Target.Text.Length > 0 && Target.Text[Target.Text.Length - 1] != ' ')
{
var tokens = _wordsSegmenter.GetTokens(Target.Text);
if (tokens == null || tokens.Count == 0)
{
return;
}
replaceSegment = tokens[tokens.Count - 1];
}
if (replaceSegment != null)
{
Target.Select((int)replaceSegment.SourceTextSegment.StartPosition, (int)replaceSegment.SourceTextSegment.Length);
}
string prediction = (sender as Button).Content.ToString();
var dataPackage = new DataPackage();
dataPackage.SetText(prediction);
Clipboard.SetContent(dataPackage);
Target.PasteFromClipboard();
UpdatePredictions();
}
private List<string> GetPrevWords()
{
var segments = _wordsSegmenter.GetTokens(Target.Text);
if ((segments == null) || (segments.Count == 0))
{
return null;
}
int i = 0;
var words = new List<string>(segments.Count);
foreach (var segment in segments)
{
words.Add(segment.Text);
i++;
}
words.Reverse();
return words;
}
private async void UpdateNextWordPredictions()
{
var prevWords = GetPrevWords();
var predictions = await _textPredictionGenerator.GetNextWordCandidatesAsync((uint)PredictionTargets.Length, prevWords);
DisplayPredictions(predictions);
}
private async void UpdatePredictions()
{
// IMPORTANT: Wait for the text box to be updated with the injected keys
await Task.Delay(1);
if ((PredictionTargets == null) || (PredictionTargets.Length <= 0))
{
return;
}
var prevWords = GetPrevWords();
if ((prevWords == null) || (prevWords.Count == 0))
{
return;
}
IReadOnlyList<string> predictions;
var prevWordsExceptLast = prevWords.GetRange(1, prevWords.Count - 1);
// It looks like we need to send in a larger number than necessary to get good quality predictions.
uint maxCandidates = (uint)PredictionTargets.Length * 2;
predictions = await _textPredictionGenerator.GetCandidatesAsync(
prevWords[0],
maxCandidates,
TextPredictionOptions.Corrections | TextPredictionOptions.Predictions,
prevWordsExceptLast);
DisplayPredictions(predictions);
}
private void DisplayPredictions(IReadOnlyList<string> predictions)
{
int i;
for (i = 0; (i < predictions.Count) && (i < PredictionTargets.Length); i++)
{
PredictionTargets[i].Content = predictions[i];
}
for (; i < PredictionTargets.Length; i++)
{
PredictionTargets[i].Content = string.Empty;
}
}
}
}

Просмотреть файл

@ -0,0 +1,84 @@
<UserControl
x:Class="CommunityToolkit.Labs.Uwp.GazeControls.GazeScrollBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
mc:Ignorable="d"
d:DesignHeight="600"
d:DesignWidth="800">
<Grid>
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Width" Value="120" />
<Setter Property="Height" Value="120" />
<Setter Property="g:GazeInput.MaxDwellRepeatCount" Value="1000" />
</Style>
</Grid.Resources>
<Grid x:Name="VerticalScrollbar" Visibility="Collapsed" HorizontalAlignment="Right" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="120"/>
<RowDefinition Height="*"/>
<RowDefinition Height="120"/>
<RowDefinition Height="120"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="Black" BorderThickness="1,0,0,1">
<Button Content="&#xE70E;" Click="OnLineUpClicked"/>
</Border>
<Border Grid.Row="1" BorderBrush="Black" BorderThickness="1,0,0,1">
<Button Content="&#xE96D;" Click="OnPageUpClicked"/>
</Border>
<Border Grid.Row="2" BorderBrush="Black" BorderThickness="1,0,0,1">
<TextBlock Text="{x:Bind Mode=OneWay, Path=VerticalPosition}" HorizontalAlignment="Center" VerticalAlignment="Center" HorizontalTextAlignment="Center"/>
</Border>
<Border Grid.Row="3" BorderBrush="Black" BorderThickness="1,0,0,1">
<Button Content="&#xE96E;" Click="OnPageDownClicked"/>
</Border>
<Border Grid.Row="4" BorderBrush="Black" BorderThickness="1,0,0,1">
<Button Content="&#xE70D;" Click="OnLineDownClicked"/>
</Border>
</Grid>
<Grid x:Name="HorizontalScrollbar" Visibility="Collapsed" VerticalAlignment="Bottom" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition />
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" BorderBrush="Black" BorderThickness="0,1,1,0">
<Button Content="&#xE76B;" Click="OnLineLeftClicked" />
</Border>
<Border Grid.Column="1" BorderBrush="Black" BorderThickness="0,1,1,0">
<Button Content="&#xE96F;" Click="OnPageLeftClicked"/>
</Border>
<Border Grid.Column="2" BorderBrush="Black" BorderThickness="0,1,1,0" HorizontalAlignment="Stretch">
<TextBlock Text="{x:Bind Mode=OneWay, Path=HorizontalPosition}" HorizontalAlignment="Center" VerticalAlignment="Center" HorizontalTextAlignment="Center"/>
</Border>
<Border Grid.Column="3" BorderBrush="Black" BorderThickness="0,1,1,0">
<Button Content="&#xE970;" Click="OnPageRightClicked"/>
</Border>
<Border Grid.Column="4" BorderBrush="Black" BorderThickness="0,1,1,0">
<Button Content="&#xE76C;" Click="OnLineRightClicked"/>
</Border>
</Grid>
</Grid>
</UserControl>

Просмотреть файл

@ -0,0 +1,170 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
/// <summary>
/// Gaze optimized scrollbar
/// </summary>
public sealed partial class GazeScrollBar : UserControl
{
private ScrollViewer _scrollViewer;
/// <summary>
/// Idetifies the Orientation dependency property
/// </summary>
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(GazeScrollBar), null);
/// <summary>
/// Gets or sets the Orientation of the gaze optimized scrollbar
/// </summary>
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Identifies the HorizontalPosition dependency property
/// </summary>
private static readonly DependencyProperty HorizontalPositionProperty =
DependencyProperty.Register("HorizontalPosition", typeof(string), typeof(GazeScrollBar), null);
/// <summary>
/// Gets or sets the percentage of the scrollable content that is to the left of the viewport
/// </summary>
private string HorizontalPosition
{
get { return (string)GetValue(HorizontalPositionProperty); }
set { SetValue(HorizontalPositionProperty, value); }
}
/// <summary>
/// Identifies the VerticalPosition dependency property
/// </summary>
private static readonly DependencyProperty VerticalPositionProperty =
DependencyProperty.Register("VerticalPosition", typeof(string), typeof(GazeScrollBar), null);
/// <summary>
/// Gets or sets the percentage of the scrollable content that is to the left of the viewport
/// </summary>
private string VerticalPosition
{
get { return (string)GetValue(VerticalPositionProperty); }
set { SetValue(VerticalPositionProperty, value); }
}
/// <summary>
/// Gets or sets the line height for scrolling with the gaze optimized scrollbar
/// </summary>
public double LineHeight { get; set; }
/// <summary>
/// Gets or sets the line width for scrolling with the gaze optimized scrollbar
/// </summary>
public double LineWidth { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="GazeScrollBar"/> class.
/// </summary>
public GazeScrollBar()
{
InitializeComponent();
}
/// <summary>
/// Attaches this scrollbar to the given ScrollViewer and enables controlling the scroll viewer
/// by clicking the buttons on this scrollbar
/// </summary>
/// <param name="scrollViewer">The ScrollViewer to attach to</param>
public void AttachTo(ScrollViewer scrollViewer)
{
_scrollViewer = scrollViewer;
_scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
_scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
_scrollViewer.ViewChanged += this.OnScrollViewerViewChanged;
_scrollViewer.Loaded += OnScrollViewerLoaded;
}
private void OnScrollViewerLoaded(object sender, RoutedEventArgs e)
{
if (Orientation == Orientation.Horizontal)
{
HorizontalScrollbar.Visibility = Visibility.Visible;
}
else
{
VerticalScrollbar.Visibility = Visibility.Visible;
}
HorizontalPosition = "0%";
VerticalPosition = "0%";
}
private void OnScrollViewerViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (Orientation == Orientation.Horizontal)
{
HorizontalPosition = $"{(int)(_scrollViewer.HorizontalOffset / _scrollViewer.ExtentWidth * 100)}%";
}
else
{
VerticalPosition = $"{(int)(_scrollViewer.VerticalOffset / _scrollViewer.ExtentHeight * 100)}%";
}
}
private void OnLineUpClicked(object sender, RoutedEventArgs e)
{
var delta = LineHeight > 0 ? LineHeight : 1;
_scrollViewer.ChangeView(null, _scrollViewer.VerticalOffset - delta, null);
}
private void OnPageUpClicked(object sender, RoutedEventArgs e)
{
var delta = _scrollViewer.ViewportHeight;
_scrollViewer.ChangeView(null, _scrollViewer.VerticalOffset - delta, null);
}
private void OnPageDownClicked(object sender, RoutedEventArgs e)
{
var delta = _scrollViewer.ViewportHeight;
_scrollViewer.ChangeView(null, _scrollViewer.VerticalOffset + delta, null);
}
private void OnLineDownClicked(object sender, RoutedEventArgs e)
{
var delta = LineHeight > 0 ? LineHeight : 1;
_scrollViewer.ChangeView(null, _scrollViewer.VerticalOffset + delta, null);
}
private void OnLineLeftClicked(object sender, RoutedEventArgs e)
{
var delta = LineWidth > 0 ? LineWidth : 1;
_scrollViewer.ChangeView(_scrollViewer.HorizontalOffset - delta, null, null);
}
private void OnPageLeftClicked(object sender, RoutedEventArgs e)
{
var delta = _scrollViewer.ViewportWidth;
_scrollViewer.ChangeView(_scrollViewer.HorizontalOffset - delta, null, null);
}
private void OnPageRightClicked(object sender, RoutedEventArgs e)
{
var delta = _scrollViewer.ViewportWidth;
_scrollViewer.ChangeView(_scrollViewer.HorizontalOffset + delta, null, null);
}
private void OnLineRightClicked(object sender, RoutedEventArgs e)
{
var delta = LineWidth > 0 ? LineWidth : 1;
_scrollViewer.ChangeView(_scrollViewer.HorizontalOffset + delta, null, null);
}
}
}

Просмотреть файл

@ -0,0 +1,268 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
/// <summary>
/// Enumeration for the type of key in the layout file.
/// </summary>
public enum KeyTypeValue
{
/// <summary>
/// The key is a normal button that injects keys into its target
/// </summary>
Normal,
/// <summary>
/// The key is a toggle button that is used to change the state of keyboard
/// </summary>
Toggle,
/// <summary>
/// The key loads a different layout page
/// </summary>
Layout
}
/// <summary>
/// Gaze optimized soft keyboard with support for custom layouts and predictions
/// </summary>
public sealed partial class GazeKeyboard : UserControl
{
/// <summary>
/// The KeyType property allows users to specify the type of a key in the layout file. <see cref="KeyTypeValue"/>
/// </summary>
public static readonly DependencyProperty KeyTypeProperty =
DependencyProperty.RegisterAttached("KeyType", typeof(KeyTypeValue), typeof(GazeKeyboard), new PropertyMetadata(KeyTypeValue.Normal));
/// <summary>
/// Gets the key type
/// </summary>
/// <param name="obj"> DependencyObject</param>
/// <returns>KeyTypeValue</returns>
public static KeyTypeValue GetKeyType(DependencyObject obj)
{
return (KeyTypeValue)obj.GetValue(KeyTypeProperty);
}
/// <summary>
/// Sets the key type
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">KeyTypeValue to set</param>
public static void SetKeyType(DependencyObject obj, KeyTypeValue value)
{
obj.SetValue(KeyTypeProperty, value);
}
/// <summary>
/// The VK property specifies the virtual key to inject into the target when a key is pressed
/// </summary>
public static readonly DependencyProperty VKProperty =
DependencyProperty.RegisterAttached("VK", typeof(int), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Gets the virtual key that will be injected
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>The virtual key as an integer</returns>
public static int GetVK(DependencyObject obj)
{
return (int)obj.GetValue(VKProperty);
}
/// <summary>
/// Sets the virtual key to be injected
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">The virtual key as an integer</param>
public static void SetVK(DependencyObject obj, int value)
{
obj.SetValue(VKProperty, value);
}
/// <summary>
/// The Unicode property indicates the unicode string that will be injected when a key is pressed
/// </summary>
public static readonly DependencyProperty UnicodeProperty =
DependencyProperty.RegisterAttached("Unicode", typeof(string), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Gets the unicode string that will be injected
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>The unicode value as a string</returns>
public static string GetUnicode(DependencyObject obj)
{
return obj.GetValue(UnicodeProperty) as string;
}
/// <summary>
/// Sets the unicode string to be injected
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">The unicode value as a string</param>
public static void SetUnicode(DependencyObject obj, string value)
{
obj.SetValue(UnicodeProperty, value);
}
/// <summary>
/// The VKList property specifies a list of virtual keys to be injected when a key is pressed
/// </summary>
public static readonly DependencyProperty VKListProperty =
DependencyProperty.RegisterAttached("VKList", typeof(List<int>), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Returns the list of virtual keys
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>A list of integers that represent virtual key codes</returns>
public static List<int> GetVKList(DependencyObject obj)
{
var value = obj.GetValue(VKListProperty);
var list = value as List<int>;
if (list == null)
{
list = new List<int>();
SetVKList(obj, list);
}
return list;
}
/// <summary>
/// Sets the list of virtual key codes to be injected
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">List of virtual key codes</param>
public static void SetVKList(DependencyObject obj, List<int> value)
{
obj.SetValue(VKListProperty, value);
}
/// <summary>
/// The PageList property specifies the list of pages in a keyboard layout
/// </summary>
public static readonly DependencyProperty PageListProperty =
DependencyProperty.RegisterAttached("PageList", typeof(List<string>), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Gets the list of pages in a layout
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>List of pages</returns>
public static List<string> GetPageList(DependencyObject obj)
{
var value = obj.GetValue(PageListProperty);
var list = value as List<string>;
if (list == null)
{
list = new List<string>();
SetPageList(obj, list);
}
return list;
}
/// <summary>
/// Sets the list of pages for a layout
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">List of pages</param>
public static void SetPageList(DependencyObject obj, List<string> value)
{
obj.SetValue(PageListProperty, value);
}
/// <summary>
/// The PageContainer property specifies the container page for a layout
/// </summary>
public static readonly DependencyProperty PageContainerProperty =
DependencyProperty.RegisterAttached("PageContainer", typeof(string), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Gets the container for a page in a layout
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>The container for a page</returns>
public static string GetPageContainer(DependencyObject obj)
{
return obj.GetValue(PageContainerProperty) as string;
}
/// <summary>
/// Sets the container for a page in a layout
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">The container for a page</param>
public static void SetPageContainer(DependencyObject obj, string value)
{
obj.SetValue(PageContainerProperty, value);
}
/// <summary>
/// The TemporaryPage property specifies a temporary layout to be loaded. This layout is changed back
/// as soon as a single key is presssed
/// </summary>
public static readonly DependencyProperty TemporaryPageProperty =
DependencyProperty.RegisterAttached("TemporaryPage", typeof(string), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Gets the temporary page to load
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>The temporary page to load</returns>
public static string GetTemporaryPage(DependencyObject obj)
{
return obj.GetValue(TemporaryPageProperty) as string;
}
/// <summary>
/// Sets the temporary page to load
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">The temporary page to load</param>
public static void SetTemporaryPage(DependencyObject obj, string value)
{
obj.SetValue(TemporaryPageProperty, value);
}
/// <summary>
/// The NewPage property specifies a new layout to load when a key is a pressed
/// </summary>
public static readonly DependencyProperty NewPageProperty =
DependencyProperty.RegisterAttached("NewPage", typeof(string), typeof(GazeKeyboard), new PropertyMetadata(0));
/// <summary>
/// Gets the new page to load
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <returns>The new page</returns>
public static string GetNewPage(DependencyObject obj)
{
return obj.GetValue(NewPageProperty) as string;
}
/// <summary>
/// Sets the new page to load
/// </summary>
/// <param name="obj">DependencyObject</param>
/// <param name="value">The new page</param>
public static void SetNewPage(DependencyObject obj, string value)
{
obj.SetValue(NewPageProperty, value);
}
}
}

Просмотреть файл

@ -0,0 +1,117 @@
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:k="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Style x:Key="Alpha" TargetType="ButtonBase">
<Setter Property="FontSize" Value="30"/>
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
<Setter Property="g:GazeInput.RepeatDelayDuration" Value="0:0:0.8"/>
<Setter Property="g:GazeInput.MaxDwellRepeatCount" Value="1" />
</Style>
<Style x:Key="Symbol" TargetType="ButtonBase">
<Setter Property="FontSize" Value="50"/>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
<ColumnDefinition MinWidth="150" Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="0" />
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="1" />
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="2" />
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="3" />
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="4" />
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="5" />
<Button Grid.Row="0" Grid.Column="6" Style="{StaticResource Alpha}" Content="6" />
<Button Grid.Row="0" Grid.Column="7" Style="{StaticResource Alpha}" Content="7" />
<Button Grid.Row="0" Grid.Column="8" Style="{StaticResource Alpha}" Content="8" />
<Button Grid.Row="0" Grid.Column="9" Style="{StaticResource Alpha}" Content="9" />
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="!" />
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="@" />
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="#" />
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="$" />
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="%" />
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="^" />
<Button Grid.Row="1" Grid.Column="6" Style="{StaticResource Alpha}" Content="~" />
<Button Grid.Row="1" Grid.Column="7" Style="{StaticResource Alpha}" Content="-" />
<Button Grid.Row="1" Grid.Column="8" Style="{StaticResource Alpha}" Content="_" />
<Button Grid.Row="1" Grid.Column="9" Style="{StaticResource Alpha}" Content="." />
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Alpha}" Content="q" />
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content="w" />
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="e" />
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="r" />
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Alpha}" Content="t" />
<Button Grid.Row="2" Grid.Column="5" Style="{StaticResource Alpha}" Content="y" />
<Button Grid.Row="2" Grid.Column="6" Style="{StaticResource Alpha}" Content="u" />
<Button Grid.Row="2" Grid.Column="7" Style="{StaticResource Alpha}" Content="i" />
<Button Grid.Row="2" Grid.Column="8" Style="{StaticResource Alpha}" Content="o" />
<Button Grid.Row="2" Grid.Column="9" Style="{StaticResource Alpha}" Content="p" />
<Button Grid.Row="3" Grid.Column="0" Style="{StaticResource Alpha}" Content="a" />
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource Alpha}" Content="s" />
<Button Grid.Row="3" Grid.Column="2" Style="{StaticResource Alpha}" Content="d" />
<Button Grid.Row="3" Grid.Column="3" Style="{StaticResource Alpha}" Content="f" />
<Button Grid.Row="3" Grid.Column="4" Style="{StaticResource Alpha}" Content="g" />
<Button Grid.Row="3" Grid.Column="5" Style="{StaticResource Alpha}" Content="h" />
<Button Grid.Row="3" Grid.Column="6" Style="{StaticResource Alpha}" Content="j" />
<Button Grid.Row="3" Grid.Column="7" Style="{StaticResource Alpha}" Content="k" />
<Button Grid.Row="3" Grid.Column="8" Style="{StaticResource Alpha}" Content="l" />
<Button Grid.Row="3" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE750;" k:GazeKeyboard.VK="8"/>
<Button Grid.Row="4" Grid.Column="0" Style="{StaticResource Alpha}" Content="z" />
<Button Grid.Row="4" Grid.Column="1" Style="{StaticResource Alpha}" Content="x" />
<Button Grid.Row="4" Grid.Column="2" Style="{StaticResource Alpha}" Content="c" />
<Button Grid.Row="4" Grid.Column="3" Style="{StaticResource Alpha}" Content="v" />
<Button Grid.Row="4" Grid.Column="4" Style="{StaticResource Symbol}" Content="&#xE75D;" Grid.ColumnSpan="2" k:GazeKeyboard.VK="32"/>
<Button Grid.Row="4" Grid.Column="6" Style="{StaticResource Alpha}" Content="b" />
<Button Grid.Row="4" Grid.Column="7" Style="{StaticResource Alpha}" Content="n" />
<Button Grid.Row="4" Grid.Column="8" Style="{StaticResource Alpha}" Content="m" />
<Button Grid.Row="4" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE74D;">
<k:GazeKeyboard.VKList>
<x:Int32>17</x:Int32> <!-- VK_CONTROL -->
<x:Int32>65</x:Int32> <!-- VK_A -->
<x:Int32>8</x:Int32> <!-- VK_BACK -->
<x:Int32>8</x:Int32> <!-- VK_BACK -->
<x:Int32>65</x:Int32> <!-- VK_A -->
<x:Int32>17</x:Int32> <!-- VK_CONTROL -->
</k:GazeKeyboard.VKList>
</Button>
</Grid>

Просмотреть файл

@ -0,0 +1,400 @@
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:k="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
x:Name="FullKeyboard">
<k:GazeKeyboard.PageList>
<x:String>MainPage</x:String>
<x:String>UppercasePage</x:String>
<x:String>NumbersPage</x:String>
<x:String>EmojiPage</x:String>
</k:GazeKeyboard.PageList>
<Grid.Resources>
<Style x:Key="Alpha" TargetType="ButtonBase">
<Setter Property="FontSize" Value="30"/>
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
<Setter Property="g:GazeInput.RepeatDelayDuration" Value="0:0:0.8"/>
<Setter Property="g:GazeInput.MaxDwellRepeatCount" Value="1" />
</Style>
<Style x:Key="Symbol" TargetType="ButtonBase">
<Setter Property="FontSize" Value="50"/>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
</Style>
</Grid.Resources>
<Grid x:Name="MainPage">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="q" />
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="w" />
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="e" />
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="r" />
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="t" />
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="y" />
<Button Grid.Row="0" Grid.Column="6" Style="{StaticResource Alpha}" Content="u" />
<Button Grid.Row="0" Grid.Column="7" Style="{StaticResource Alpha}" Content="i" />
<Button Grid.Row="0" Grid.Column="8" Style="{StaticResource Alpha}" Content="o" />
<Button Grid.Row="0" Grid.Column="9" Style="{StaticResource Alpha}" Content="p" />
<Button Grid.Row="0" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE750;" k:GazeKeyboard.VK="8"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="a" />
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="s" />
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="d" />
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="f" />
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="g" />
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="h" />
<Button Grid.Row="1" Grid.Column="6" Style="{StaticResource Alpha}" Content="j" />
<Button Grid.Row="1" Grid.Column="7" Style="{StaticResource Alpha}" Content="k" />
<Button Grid.Row="1" Grid.Column="8" Style="{StaticResource Alpha}" Content="l" />
<Button Grid.Row="1" Grid.Column="9" Style="{StaticResource Alpha}" Content="'" />
<Button Grid.Row="1" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE751;" k:GazeKeyboard.VK="13"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Symbol}" Content="&#xE752;" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.TemporaryPage="UppercasePage" />
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content="z" />
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="x" />
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="c" />
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Alpha}" Content="v" />
<Button Grid.Row="2" Grid.Column="5" Style="{StaticResource Alpha}" Content="b" />
<Button Grid.Row="2" Grid.Column="6" Style="{StaticResource Alpha}" Content="n" />
<Button Grid.Row="2" Grid.Column="7" Style="{StaticResource Alpha}" Content="m" />
<Button Grid.Row="2" Grid.Column="8" Style="{StaticResource Alpha}" Content="," />
<Button Grid.Row="2" Grid.Column="9" Style="{StaticResource Alpha}" Content="." />
<Button Grid.Row="2" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE892;">
<k:GazeKeyboard.VKList>
<x:Int32>17</x:Int32>
<!-- VK_CONTROL -->
<x:Int32>65</x:Int32>
<!-- VK_A -->
<x:Int32>8</x:Int32>
<!-- VK_BACK -->
<x:Int32>8</x:Int32>
<!-- VK_BACK -->
<x:Int32>65</x:Int32>
<!-- VK_A -->
<x:Int32>17</x:Int32>
<!-- VK_CONTROL -->
</k:GazeKeyboard.VKList>
</Button>
<Button Grid.Row="3" Grid.Column="0" Style="{StaticResource Alpha}" Content="123" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="NumbersPage"/>
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource Alpha}" Content="Ctrl" />
<Button Grid.Row="3" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE76E;" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="EmojiPage"/>
<Button Grid.Row="3" Grid.Column="3" Style="{StaticResource Symbol}" Content="&#xE75D;" Grid.ColumnSpan="4" k:GazeKeyboard.VK="32"/>
<Button Grid.Row="3" Grid.Column="7" Style="{StaticResource Symbol}" Content="&#xEC52;" k:GazeKeyboard.VK="37" />
<Button Grid.Row="3" Grid.Column="8" Style="{StaticResource Symbol}" Content="&#xEBE7;" k:GazeKeyboard.VK="39" />
<Button Grid.Row="3" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE74A;" k:GazeKeyboard.VK="38" />
<Button Grid.Row="3" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE74B;" k:GazeKeyboard.VK="40" />
</Grid>
<Grid x:Name="UppercasePage" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="Q" />
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="W" />
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="E" />
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="R" />
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="T" />
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="Y" />
<Button Grid.Row="0" Grid.Column="6" Style="{StaticResource Alpha}" Content="U" />
<Button Grid.Row="0" Grid.Column="7" Style="{StaticResource Alpha}" Content="I" />
<Button Grid.Row="0" Grid.Column="8" Style="{StaticResource Alpha}" Content="O" />
<Button Grid.Row="0" Grid.Column="9" Style="{StaticResource Alpha}" Content="P" />
<Button Grid.Row="0" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE750;" k:GazeKeyboard.VK="8"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="A" />
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="S" />
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="D" />
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="F" />
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="G" />
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="H" />
<Button Grid.Row="1" Grid.Column="6" Style="{StaticResource Alpha}" Content="J" />
<Button Grid.Row="1" Grid.Column="7" Style="{StaticResource Alpha}" Content="K" />
<Button Grid.Row="1" Grid.Column="8" Style="{StaticResource Alpha}" Content="L" />
<Button Grid.Row="1" Grid.Column="9" Style="{StaticResource Alpha}" Content="'" />
<Button Grid.Row="1" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE751;" k:GazeKeyboard.VK="13"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Symbol}" Content="&#xE752;" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="MainPage" />
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content="Z" />
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="X" />
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="C" />
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Alpha}" Content="V" />
<Button Grid.Row="2" Grid.Column="5" Style="{StaticResource Alpha}" Content="B" />
<Button Grid.Row="2" Grid.Column="6" Style="{StaticResource Alpha}" Content="N" />
<Button Grid.Row="2" Grid.Column="7" Style="{StaticResource Alpha}" Content="M" />
<Button Grid.Row="2" Grid.Column="8" Style="{StaticResource Alpha}" Content="," />
<Button Grid.Row="2" Grid.Column="9" Style="{StaticResource Alpha}" Content="." />
<Button Grid.Row="2" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE892;">
<k:GazeKeyboard.VKList>
<x:Int32>17</x:Int32>
<!-- VK_CONTROL -->
<x:Int32>65</x:Int32>
<!-- VK_A -->
<x:Int32>8</x:Int32>
<!-- VK_BACK -->
<x:Int32>8</x:Int32>
<!-- VK_BACK -->
<x:Int32>65</x:Int32>
<!-- VK_A -->
<x:Int32>17</x:Int32>
<!-- VK_CONTROL -->
</k:GazeKeyboard.VKList>
</Button>
<Button Grid.Row="3" Grid.Column="0" Style="{StaticResource Alpha}" Content="123" />
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource Alpha}" Content="Ctrl" />
<Button Grid.Row="3" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE76E;" />
<Button Grid.Row="3" Grid.Column="3" Style="{StaticResource Symbol}" Content="&#xE75D;" Grid.ColumnSpan="4" k:GazeKeyboard.VK="32"/>
<Button Grid.Row="3" Grid.Column="7" Style="{StaticResource Symbol}" Content="&#xEC52;" k:GazeKeyboard.VK="37" />
<Button Grid.Row="3" Grid.Column="8" Style="{StaticResource Symbol}" Content="&#xEBE7;" k:GazeKeyboard.VK="39" />
<Button Grid.Row="3" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE74A;" k:GazeKeyboard.VK="38" />
<Button Grid.Row="3" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE74B;" k:GazeKeyboard.VK="40" />
</Grid>
<Grid x:Name="NumbersPage" Visibility="Collapsed">
<k:GazeKeyboard.PageList>
<x:String>SymbolsPage</x:String>
</k:GazeKeyboard.PageList>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="Tab" k:GazeKeyboard.VK="9"/>
<Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="3" Grid.ColumnSpan="6" x:Name="SymbolsPage">
<k:GazeKeyboard.PageList>
<x:String>SymbolsPage1</x:String>
<x:String>SymbolsPage2</x:String>
</k:GazeKeyboard.PageList>
<Grid x:Name="SymbolsPage1" Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="!" />
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="@" />
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="#" />
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="$" />
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="%" />
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="&amp;" />
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="(" />
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content=")" />
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="-" />
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="_" />
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="=" />
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="+" />
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Alpha}" Content="\" />
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content=";" />
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content=":" />
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="&quot;" />
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Alpha}" Content="*" />
<Button Grid.Row="2" Grid.Column="5" Style="{StaticResource Alpha}" Content="/" />
</Grid>
<Grid x:Name="SymbolsPage2" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="•" />
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="©" />
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="€" />
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="£" />
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="µ" />
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="½" />
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="&lt;" />
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="&gt;" />
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="[" />
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="]" />
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="{}{" />
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="}" />
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Alpha}" Content="|" />
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content="¦" />
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="¶" />
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="°" />
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Alpha}" Content="~" />
<Button Grid.Row="2" Grid.Column="5" Style="{StaticResource Alpha}" Content="^" />
</Grid>
</Grid>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Symbol}" Content="&#xE760;" k:GazeKeyboard.PageContainer="SymbolsPage" k:GazeKeyboard.NewPage="SymbolsPage1"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Symbol}" Content="&#xE761;" k:GazeKeyboard.PageContainer="SymbolsPage" k:GazeKeyboard.NewPage="SymbolsPage2"/>
<Button Grid.Row="3" Grid.Column="0" Style="{StaticResource Alpha}" Content="abc" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource Alpha}" Content="Ctrl" />
<Button Grid.Row="3" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE76E;" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="EmojiPage"/>
<Button Grid.Row="0" Grid.Column="7" Style="{StaticResource Alpha}" Content="1" />
<Button Grid.Row="0" Grid.Column="8" Style="{StaticResource Alpha}" Content="2" />
<Button Grid.Row="0" Grid.Column="9" Style="{StaticResource Alpha}" Content="3" />
<Button Grid.Row="1" Grid.Column="7" Style="{StaticResource Alpha}" Content="4" />
<Button Grid.Row="1" Grid.Column="8" Style="{StaticResource Alpha}" Content="5" />
<Button Grid.Row="1" Grid.Column="9" Style="{StaticResource Alpha}" Content="6" />
<Button Grid.Row="2" Grid.Column="7" Style="{StaticResource Alpha}" Content="7" />
<Button Grid.Row="2" Grid.Column="8" Style="{StaticResource Alpha}" Content="8" />
<Button Grid.Row="2" Grid.Column="9" Style="{StaticResource Alpha}" Content="9" />
<Button Grid.Row="3" Grid.Column="7" Style="{StaticResource Alpha}" Content="0" Grid.ColumnSpan="2"/>
<Button Grid.Row="3" Grid.Column="9" Style="{StaticResource Alpha}" Content="." />
<Button Grid.Row="3" Grid.Column="3" Style="{StaticResource Symbol}" Content="&#xEC52;" k:GazeKeyboard.VK="37" />
<Button Grid.Row="3" Grid.Column="4" Style="{StaticResource Symbol}" Content="&#xEBE7;" k:GazeKeyboard.VK="39" />
<Button Grid.Row="3" Grid.Column="5" Style="{StaticResource Symbol}" Content="&#xE75D;" Grid.ColumnSpan="2" k:GazeKeyboard.VK="32"/>
<Button Grid.Row="0" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE750;" k:GazeKeyboard.VK="8"/>
<Button Grid.Row="1" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE751;" k:GazeKeyboard.VK="13" Grid.RowSpan="3"/>
</Grid>
<Grid x:Name="EmojiPage" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="&#x1f600;" k:GazeKeyboard.Unicode="&#x1f600;"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="&#x1f601;" k:GazeKeyboard.Unicode="&#x1f601;"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="&#x1f602;" k:GazeKeyboard.Unicode="&#x1f602;"/>
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="&#x1f603;" k:GazeKeyboard.Unicode="&#x1f603;"/>
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="&#x1f604;" k:GazeKeyboard.Unicode="&#x1f604;"/>
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="&#x1f605;" k:GazeKeyboard.Unicode="&#x1f605;"/>
<Button Grid.Row="0" Grid.Column="6" Style="{StaticResource Alpha}" Content="&#x1f606;" k:GazeKeyboard.Unicode="&#x1f606;"/>
<Button Grid.Row="0" Grid.Column="7" Style="{StaticResource Alpha}" Content="&#x1f607;" k:GazeKeyboard.Unicode="&#x1f607;"/>
<Button Grid.Row="0" Grid.Column="8" Style="{StaticResource Alpha}" Content="&#x1f608;" k:GazeKeyboard.Unicode="&#x1f608;"/>
<Button Grid.Row="0" Grid.Column="9" Style="{StaticResource Alpha}" Content="&#x1f609;" k:GazeKeyboard.Unicode="&#x1f609;"/>
<Button Grid.Row="0" Grid.Column="10" Style="{StaticResource Alpha}" Content="&#x1f60A;" k:GazeKeyboard.Unicode="&#x1f60A;"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="&#x1f60B;" k:GazeKeyboard.Unicode="&#x1f60B;"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="&#x1f60C;" k:GazeKeyboard.Unicode="&#x1f60C;"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="&#x1f60D;" k:GazeKeyboard.Unicode="&#x1f60D;"/>
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="&#x1f60E;" k:GazeKeyboard.Unicode="&#x1f60E;"/>
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="&#x1f60F;" k:GazeKeyboard.Unicode="&#x1f60F;"/>
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="&#x1f610;" k:GazeKeyboard.Unicode="&#x1f610;"/>
<Button Grid.Row="1" Grid.Column="6" Style="{StaticResource Alpha}" Content="&#x1f611;" k:GazeKeyboard.Unicode="&#x1f611;"/>
<Button Grid.Row="1" Grid.Column="7" Style="{StaticResource Alpha}" Content="&#x1f612;" k:GazeKeyboard.Unicode="&#x1f612;"/>
<Button Grid.Row="1" Grid.Column="8" Style="{StaticResource Alpha}" Content="&#x1f613;" k:GazeKeyboard.Unicode="&#x1f613;"/>
<Button Grid.Row="1" Grid.Column="9" Style="{StaticResource Alpha}" Content="&#x1f614;" k:GazeKeyboard.Unicode="&#x1f614;"/>
<Button Grid.Row="1" Grid.Column="10" Style="{StaticResource Alpha}" Content="&#x1f615;" k:GazeKeyboard.Unicode="&#x1f615;"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Alpha}" Content="&#x1f616;" k:GazeKeyboard.Unicode="&#x1f616;"/>
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content="&#x1f617;" k:GazeKeyboard.Unicode="&#x1f617;"/>
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="&#x1f618;" k:GazeKeyboard.Unicode="&#x1f618;"/>
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="&#x1f619;" k:GazeKeyboard.Unicode="&#x1f619;"/>
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Alpha}" Content="&#x1f61A;" k:GazeKeyboard.Unicode="&#x1f61A;"/>
<Button Grid.Row="2" Grid.Column="5" Style="{StaticResource Alpha}" Content="&#x1f61B;" k:GazeKeyboard.Unicode="&#x1f61B;"/>
<Button Grid.Row="2" Grid.Column="6" Style="{StaticResource Alpha}" Content="&#x1f61C;" k:GazeKeyboard.Unicode="&#x1f61C;"/>
<Button Grid.Row="2" Grid.Column="7" Style="{StaticResource Alpha}" Content="&#x1f61D;" k:GazeKeyboard.Unicode="&#x1f61D;"/>
<Button Grid.Row="2" Grid.Column="8" Style="{StaticResource Alpha}" Content="&#x1f61E;" k:GazeKeyboard.Unicode="&#x1f61E;"/>
<Button Grid.Row="2" Grid.Column="9" Style="{StaticResource Alpha}" Content="&#x1f61F;" k:GazeKeyboard.Unicode="&#x1f61F;"/>
<Button Grid.Row="2" Grid.Column="10" Style="{StaticResource Alpha}" Content="&#x1f620;" k:GazeKeyboard.Unicode="&#x1f620;"/>
<Button Grid.Row="3" Grid.Column="0" Style="{StaticResource Alpha}" Content="abc" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
<Button Grid.Row="3" Grid.Column="1" Style="{StaticResource Alpha}" Content="Ctrl" />
<Button Grid.Row="3" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE76E;" k:GazeKeyboard.PageContainer="FullKeyboard" k:GazeKeyboard.NewPage="EmojiPage"/>
<Button Grid.Row="3" Grid.Column="3" Style="{StaticResource Symbol}" Content="&#xE75D;" Grid.ColumnSpan="4" k:GazeKeyboard.VK="32"/>
<Button Grid.Row="3" Grid.Column="7" Style="{StaticResource Symbol}" Content="&#xEC52;" k:GazeKeyboard.VK="37" />
<Button Grid.Row="3" Grid.Column="8" Style="{StaticResource Symbol}" Content="&#xEBE7;" k:GazeKeyboard.VK="39" />
<Button Grid.Row="3" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE74A;" k:GazeKeyboard.VK="38" />
<Button Grid.Row="3" Grid.Column="10" Style="{StaticResource Symbol}" Content="&#xE74B;" k:GazeKeyboard.VK="40" />
</Grid>
</Grid>

Просмотреть файл

@ -0,0 +1,93 @@
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:k="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Style x:Key="Alpha" TargetType="ButtonBase">
<Setter Property="FontSize" Value="30"/>
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
<Setter Property="g:GazeInput.RepeatDelayDuration" Value="0:0:0.8"/>
<Setter Property="g:GazeInput.MaxDwellRepeatCount" Value="1" />
</Style>
<Style x:Key="Symbol" TargetType="ButtonBase">
<Setter Property="FontSize" Value="50"/>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="q" />
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="w" />
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="e" />
<Button Grid.Row="0" Grid.Column="3" Style="{StaticResource Alpha}" Content="r" />
<Button Grid.Row="0" Grid.Column="4" Style="{StaticResource Alpha}" Content="t" />
<Button Grid.Row="0" Grid.Column="5" Style="{StaticResource Alpha}" Content="y" />
<Button Grid.Row="0" Grid.Column="6" Style="{StaticResource Alpha}" Content="u" />
<Button Grid.Row="0" Grid.Column="7" Style="{StaticResource Alpha}" Content="i" />
<Button Grid.Row="0" Grid.Column="8" Style="{StaticResource Alpha}" Content="o" />
<Button Grid.Row="0" Grid.Column="9" Style="{StaticResource Alpha}" Content="p" />
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="a" />
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="s" />
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Alpha}" Content="d" />
<Button Grid.Row="1" Grid.Column="3" Style="{StaticResource Alpha}" Content="f" />
<Button Grid.Row="1" Grid.Column="4" Style="{StaticResource Alpha}" Content="g" />
<Button Grid.Row="1" Grid.Column="5" Style="{StaticResource Alpha}" Content="h" />
<Button Grid.Row="1" Grid.Column="6" Style="{StaticResource Alpha}" Content="j" />
<Button Grid.Row="1" Grid.Column="7" Style="{StaticResource Alpha}" Content="k" />
<Button Grid.Row="1" Grid.Column="8" Style="{StaticResource Alpha}" Content="l" />
<Button Grid.Row="1" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE750;" k:GazeKeyboard.VK="8"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Alpha}" Content="z" />
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Alpha}" Content="x" />
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="c" />
<Button Grid.Row="2" Grid.Column="3" Style="{StaticResource Alpha}" Content="v" />
<Button Grid.Row="2" Grid.Column="4" Style="{StaticResource Symbol}" Content="&#xE75D;" Grid.ColumnSpan="2" k:GazeKeyboard.VK="32"/>
<Button Grid.Row="2" Grid.Column="6" Style="{StaticResource Alpha}" Content="b" />
<Button Grid.Row="2" Grid.Column="7" Style="{StaticResource Alpha}" Content="n" />
<Button Grid.Row="2" Grid.Column="8" Style="{StaticResource Alpha}" Content="m" />
<Button Grid.Row="2" Grid.Column="9" Style="{StaticResource Symbol}" Content="&#xE74D;">
<k:GazeKeyboard.VKList>
<x:Int32>17</x:Int32> <!-- VK_CONTROL -->
<x:Int32>65</x:Int32> <!-- VK_A -->
<x:Int32>8</x:Int32> <!-- VK_BACK -->
<x:Int32>8</x:Int32> <!-- VK_BACK -->
<x:Int32>65</x:Int32> <!-- VK_A -->
<x:Int32>17</x:Int32> <!-- VK_CONTROL -->
</k:GazeKeyboard.VKList>
</Button>
</Grid>

Просмотреть файл

@ -0,0 +1,187 @@
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:k="using:CommunityToolkit.Labs.Uwp.GazeControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
x:Name="TwoStageKeyboard">
<k:GazeKeyboard.PageList>
<x:String>MainPage</x:String>
<x:String>PageABCDE</x:String>
<x:String>PageFGHIJ</x:String>
<x:String>PageKLMNO</x:String>
<x:String>PagePQRST</x:String>
<x:String>PageUVWXY</x:String>
<x:String>PageZPUNC</x:String>
</k:GazeKeyboard.PageList>
<Grid.Resources>
<Style x:Key="Alpha" TargetType="ButtonBase">
<Setter Property="FontSize" Value="30"/>
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
<Setter Property="g:GazeInput.RepeatDelayDuration" Value="0:0:0.8"/>
<Setter Property="g:GazeInput.MaxDwellRepeatCount" Value="1" />
</Style>
<Style x:Key="Symbol" TargetType="ButtonBase">
<Setter Property="FontSize" Value="50"/>
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
</Style>
</Grid.Resources>
<Grid x:Name="MainPage" Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="[a b c d e]" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.TemporaryPage="PageABCDE"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="[f g h i j]" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.TemporaryPage="PageFGHIJ"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="[k l m n o]" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.TemporaryPage="PageKLMNO"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="[p q r s t]" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.TemporaryPage="PagePQRST"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource Alpha}" Content="[u v w x y]" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.TemporaryPage="PageUVWXY"/>
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource Alpha}" Content="[z , ? &#x1F642; &#x1F641;]" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.TemporaryPage="PageZPUNC"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE750;" k:GazeKeyboard.VK="8"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE74D;">
<k:GazeKeyboard.VKList>
<x:Int32>17</x:Int32>
<!-- VK_CONTROL -->
<x:Int32>65</x:Int32>
<!-- VK_A -->
<x:Int32>8</x:Int32>
<!-- VK_BACK -->
<x:Int32>8</x:Int32>
<!-- VK_BACK -->
<x:Int32>65</x:Int32>
<!-- VK_A -->
<x:Int32>17</x:Int32>
<!-- VK_CONTROL -->
</k:GazeKeyboard.VKList>
</Button>
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource Symbol}" Content="&#xE75D;" k:GazeKeyboard.VK="32"/>
</Grid>
<Grid x:Name="PageABCDE" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="a"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="b"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="c"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="d"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="e"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE8BB;" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
</Grid>
<Grid x:Name="PageFGHIJ" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="f"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="g"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="h"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="i"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="j"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE8BB;" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
</Grid>
<Grid x:Name="PageKLMNO" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="k"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="l"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="m"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="n"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="o "/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE8BB;" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
</Grid>
<Grid x:Name="PagePQRST" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="p"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="q"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="r"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="s"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="t"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE8BB;" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
</Grid>
<Grid x:Name="PageUVWXY" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="u"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content="v"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="w"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="x"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="y"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE8BB;" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
</Grid>
<Grid x:Name="PageZPUNC" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Style="{StaticResource Alpha}" Content="z"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource Alpha}" Content=","/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource Alpha}" Content="?"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource Alpha}" Content="&#x1F642;" k:GazeKeyboard.Unicode="&#x1F642;"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource Alpha}" Content="&#x1F641;" k:GazeKeyboard.Unicode="&#x1F641;"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource Symbol}" Content="&#xE8BB;" k:GazeKeyboard.PageContainer="TwoStageKeyboard" k:GazeKeyboard.NewPage="MainPage"/>
</Grid>
</Grid>

Просмотреть файл

@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
internal class KeyboardPage
{
public FrameworkElement Page { get; set; }
public KeyboardPage Parent { get; set; }
public List<string> ChildrenNames { get; set; }
public List<KeyboardPage> Children { get; set; }
public KeyboardPage CurrentChild { get; set; }
public KeyboardPage PrevChild { get; set; }
public KeyboardPage(FrameworkElement page, KeyboardPage parent)
{
Page = page;
Parent = parent;
ChildrenNames = new List<string>();
Children = new List<KeyboardPage>();
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
internal class PathPart
{
public int Index { get; set; }
public string Name { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,44 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI;
using Windows.UI.Xaml.Controls;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
/// <summary>
/// A custom version of GridView to manage the scroll bar associated with the GridView
/// </summary>
public class ScrollGridView : GridView
{
private ScrollViewer _scrollViewer;
/// <summary>
/// Overridden version of OnApplyTemplate
/// </summary>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_scrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
if (GazeScrollBar != null)
{
GazeScrollBar.AttachTo(_scrollViewer);
}
_scrollViewer.ViewChanged += this.OnScrollViewerViewChanged;
}
private void OnScrollViewerViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
var item = this.FindDescendant<GridViewItem>();
GazeScrollBar.LineHeight = item != null ? item.ActualHeight : 1;
}
/// <summary>
/// Gets or sets the gaze optimized vertical scrollbar
/// </summary>
public GazeScrollBar GazeScrollBar { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,103 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.FileProperties;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
namespace CommunityToolkit.Labs.Uwp.GazeControls
{
internal class StorageItem : DependencyObject
{
public IStorageItem Item { get; }
public StorageItem(IStorageItem item)
{
Item = item;
}
public bool IsFolder
{
get
{
return Item.IsOfType(StorageItemTypes.Folder);
}
}
public string TextIcon
{
get
{
return IsFolder ? "\uF12B" : "\uE7C3";
}
}
public string Name
{
get
{
return Item.Name;
}
}
public string Path
{
get
{
return Item.Path;
}
}
public BitmapImage Thumbnail
{
get
{
if (_thumbnail == null)
{
if (_storageThumbnail == null)
{
return null;
}
_thumbnail = new BitmapImage();
_thumbnail.SetSource(_storageThumbnail);
}
return _thumbnail;
}
}
private BitmapImage _thumbnail;
private StorageItemThumbnail _storageThumbnail;
public async Task GetThumbnailAsync()
{
var props = Item as IStorageItemProperties;
_storageThumbnail = await props.GetThumbnailAsync(ThumbnailMode.DocumentsView);
}
internal static readonly DependencyProperty StorageThumbnailProperty =
DependencyProperty.Register(
"StorageThumbnail",
typeof(StorageItemThumbnail),
typeof(StorageItem),
null);
internal StorageItemThumbnail StorageThumbnail
{
get { return (StorageItemThumbnail)GetValue(StorageThumbnailProperty); }
set { SetValue(StorageThumbnailProperty, value); }
}
}
}

Просмотреть файл

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="EnterFilename" xml:space="preserve">
<value>Enter Filename...</value>
</data>
<data name="FileOpen.Title" xml:space="preserve">
<value>Open File</value>
</data>
<data name="FileSave.Title" xml:space="preserve">
<value>Save File</value>
</data>
<data name="NewFolder" xml:space="preserve">
<value>New Folder...</value>
</data>
<data name="OK" xml:space="preserve">
<value>OK</value>
</data>
<data name="Open" xml:space="preserve">
<value>Open</value>
</data>
<data name="OverwriteWarning" xml:space="preserve">
<value>"{0}" already exists.</value>
</data>
<data name="Save" xml:space="preserve">
<value>Save</value>
</data>
</root>

25
GazeControls.sln Normal file
Просмотреть файл

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31424.327
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommunityToolkit.Labs.Uwp.GazeControls", "CommunityToolkit.Labs.Uwp.GazeControls\CommunityToolkit.Labs.Uwp.GazeControls.csproj", "{352191F5-8704-45A1-ACB3-CA47C6898A99}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{352191F5-8704-45A1-ACB3-CA47C6898A99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{352191F5-8704-45A1-ACB3-CA47C6898A99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{352191F5-8704-45A1-ACB3-CA47C6898A99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{352191F5-8704-45A1-ACB3-CA47C6898A99}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7956E0E0-C673-4682-A631-F1AC12B65C17}
EndGlobalSection
EndGlobal

7
GazeInputTest/App.xaml Normal file
Просмотреть файл

@ -0,0 +1,7 @@
<Application
x:Class="GazeInputTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:GazeInputTest"
RequestedTheme="Light">
</Application>

100
GazeInputTest/App.xaml.cs Normal file
Просмотреть файл

@ -0,0 +1,100 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.Toolkit.Uwp.Input.GazeInteraction;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace GazeInputTest
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public sealed partial class App : Application
{
/// <summary>
/// Initializes a new instance of the <see cref="App"/> class.
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
GazeInput.Interaction = Interaction.Enabled;
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
// TODO: Save application state and stop any background activity
deferral.Complete();
}
}
}

Двоичные данные
GazeInputTest/Assets/LockScreenLogo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
GazeInputTest/Assets/SplashScreen.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.5 KiB

Двоичные данные
GazeInputTest/Assets/Square150x150Logo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Двоичные данные
GazeInputTest/Assets/Square44x44Logo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Двоичные данные
GazeInputTest/Assets/StoreLogo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.4 KiB

Двоичные данные
GazeInputTest/Assets/Wide310x150Logo.scale-200.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.1 KiB

Просмотреть файл

@ -0,0 +1,164 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{A122EA02-4DE7-413D-BFBF-AF7DFC668DD6}</ProjectGuid>
<OutputType>AppContainerExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GazeInputTest</RootNamespace>
<AssemblyName>GazeInputTest</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<NoWarn>$(NoWarn);2008</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
<OutputPath>bin\ARM64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<ItemGroup>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Properties\Default.rd.xml" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="MainPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.12</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.Input.GazeControls\Microsoft.Toolkit.Uwp.Input.GazeControls.csproj">
<Project>{fa4682b6-26be-49a0-be97-96956724ae55}</Project>
<Name>Microsoft.Toolkit.Uwp.Input.GazeControls</Name>
</ProjectReference>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.Input.GazeInteraction\Microsoft.Toolkit.Uwp.Input.GazeInteraction.csproj">
<Project>{5bf75694-798a-43a0-8150-415de195359c}</Project>
<Name>Microsoft.Toolkit.Uwp.Input.GazeInteraction</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- No-op to avoid build error when packing solution from commandline -->
<Target Name="Pack" />
</Project>

108
GazeInputTest/MainPage.xaml Normal file
Просмотреть файл

@ -0,0 +1,108 @@
<Page
x:Class="GazeInputTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:GazeInputTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:g="using:Microsoft.Toolkit.Uwp.Input.GazeInteraction"
xmlns:k="using:Microsoft.Toolkit.Uwp.Input.GazeControls"
g:GazeInput.Interaction="Enabled"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="10" />
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
</Style>
<Style TargetType="ToggleButton">
<Setter Property="Margin" Value="10" />
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
</Style>
<Style x:Key="Alpha" TargetType="ButtonBase">
<Setter Property="FontSize" Value="30"/>
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="AllowFocusOnInteraction" Value="False" />
<Setter Property="g:GazeInput.RepeatDelayDuration" Value="0:0:0.8"/>
<Setter Property="g:GazeInput.MaxDwellRepeatCount" Value="1" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*"/>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton Grid.Row="0" x:Name="ShowCursor" Checked="ShowCursor_Toggle" Unchecked="ShowCursor_Toggle" Content="Show Cursor"/>
<Button Grid.Row="1" x:Name="Dwell" Click="Dwell_Click" Content="Eyes Here">
<g:GazeInput.GazeElement>
<g:GazeElement StateChanged="OnStateChanged"/>
</g:GazeInput.GazeElement>
</Button>
<Button Grid.Row="2" x:Name="HowButton" Content="0: Idle" Click="OnLegacyInvoked" g:GazeInput.MaxDwellRepeatCount="4" >
<g:GazeInput.GazeElement>
<g:GazeElement Invoked="OnGazeInvoked"/>
</g:GazeInput.GazeElement>
</Button>
<ToggleButton Grid.Row="3" Content="Click" g:GazeInput.DwellDuration="0:0:2" >
<g:GazeInput.GazeElement>
<g:GazeElement DwellProgressFeedback="OnInvokeProgress" />
</g:GazeInput.GazeElement>
</ToggleButton>
<Button Grid.Row="4" Content="Open File" Click="OnOpenFile"/>
</Grid>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="15*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="75*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" x:Name="TheTextBox" HorizontalAlignment="Stretch" FontSize="18"/>
<Button Grid.Column="1" Content="Play" Click="OnPlay"/>
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Center">
<Button x:Name="Prediction0" Height="100" MinWidth="300" Style="{StaticResource Alpha}" />
<Button x:Name="Prediction1" Height="100" MinWidth="300" Style="{StaticResource Alpha}" />
<Button x:Name="Prediction2" Height="100" MinWidth="300" Style="{StaticResource Alpha}" />
</StackPanel>
<k:GazeKeyboard Grid.Row="2" x:Name="GazeKeyboard"/>
</Grid>
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical">
<ProgressBar x:Name="ProgressShow" Maximum="100" />
<TextBlock Grid.Column="0" x:Name="DeviceAvailable" Text="Device availability not yet detected"/>
</StackPanel>
<ToggleButton Grid.Row="1" Content="Pause/Resume" Click="OnPauseResume"/>
<Button Grid.Row="2" Content="Spawn" Click="OnSpawnClicked"/>
<Button Grid.Row="3" Content="Change Layout" Click="OnChangeLayout"/>
<Button Grid.Row="4" Content="Save File" Click="OnSaveFile"/>
</Grid>
</Grid>
</Page>

Просмотреть файл

@ -0,0 +1,181 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.Input.GazeControls;
using Microsoft.Toolkit.Uwp.Input.GazeInteraction;
using Windows.ApplicationModel.Core;
using Windows.Media.SpeechSynthesis;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace GazeInputTest
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private StorageFolder _layoutsFolder;
private MediaElement _mediaElement;
private SpeechSynthesizer _speechSynthesizer;
public MainPage()
{
this.InitializeComponent();
ShowCursor.IsChecked = GazeInput.GetIsCursorVisible(this);
_mediaElement = new MediaElement();
_speechSynthesizer = new SpeechSynthesizer();
GazeInput.IsDeviceAvailableChanged += GazeInput_IsDeviceAvailableChanged;
GazeInput_IsDeviceAvailableChanged(null, null);
Loaded += this.OnMainPageLoaded;
}
private async void OnMainPageLoaded(object sender, RoutedEventArgs e)
{
var uri = new Uri($"ms-appx:///Microsoft.Toolkit.Uwp.Input.GazeControls/KeyboardLayouts/MinAAC.xaml");
var layoutFile = await StorageFile.GetFileFromApplicationUriAsync(uri);
_layoutsFolder = await layoutFile.GetParentAsync();
await GazeKeyboard.TryLoadLayoutAsync(layoutFile);
GazeKeyboard.Target = TheTextBox;
GazeKeyboard.PredictionTargets = new Button[] { Prediction0, Prediction1, Prediction2 };
}
private void GazeInput_IsDeviceAvailableChanged(object sender, object e)
{
DeviceAvailable.Text = GazeInput.IsDeviceAvailable ? "Eye tracker device available" : "No eye tracker device available";
}
private void OnStateChanged(object sender, StateChangedEventArgs ea)
{
Dwell.Content = ea.PointerState.ToString();
}
private void Dwell_Click(object sender, RoutedEventArgs e)
{
Dwell.Content = "Clicked";
}
private void ShowCursor_Toggle(object sender, RoutedEventArgs e)
{
if (ShowCursor.IsChecked.HasValue)
{
GazeInput.SetIsCursorVisible(this, ShowCursor.IsChecked.Value);
}
}
private int _clickCount;
private void OnLegacyInvoked(object sender, RoutedEventArgs e)
{
_clickCount++;
HowButton.Content = string.Format("{0}: Legacy click", _clickCount);
}
private void OnGazeInvoked(object sender, DwellInvokedRoutedEventArgs e)
{
_clickCount++;
HowButton.Content = string.Format("{0}: Accessible click", _clickCount);
e.Handled = true;
}
private void OnInvokeProgress(object sender, DwellProgressEventArgs e)
{
if (e.State == DwellProgressState.Progressing)
{
ProgressShow.Value = 100.0 * e.Progress;
}
ProgressShow.IsIndeterminate = e.State == DwellProgressState.Complete;
e.Handled = true;
}
private async void OnSpawnClicked(object sender, RoutedEventArgs e)
{
var newView = CoreApplication.CreateNewView();
var newViewId = 0;
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
{
var frame = new Frame();
frame.Navigate(typeof(MainPage), newViewId);
Window.Current.Content = frame;
// In Windows 10 UWP we need to activate our view first.
// Let's do it now so that we can use TryShow...() and SwitchAsync().
Window.Current.Activate();
newViewId = ApplicationView.GetForCurrentView().Id;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);
}
private async void OnChangeLayout(object sender, RoutedEventArgs e)
{
var picker = new GazeFileOpenPicker();
var library = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Documents);
picker.Favorites = new List<StorageFolder>();
picker.Favorites.Add(_layoutsFolder);
picker.Favorites.Add(library.SaveFolder);
picker.FileTypeFilter.Add(".xaml");
picker.CurrentFolder = library.SaveFolder;
await picker.ShowAsync();
var file = picker.SelectedItem;
if (file != null)
{
await GazeKeyboard.TryLoadLayoutAsync(file);
}
}
private async void OnOpenFile(object sender, RoutedEventArgs e)
{
var picker = new GazeFileOpenPicker();
var library = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Documents);
picker.FileTypeFilter.Add(".txt");
picker.CurrentFolder = library.SaveFolder;
await picker.ShowAsync();
var file = picker.SelectedItem;
if (file != null)
{
TheTextBox.Text = await FileIO.ReadTextAsync(file);
}
}
private async void OnSaveFile(object sender, RoutedEventArgs e)
{
var picker = new GazeFileSavePicker();
var library = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Documents);
picker.FileTypeFilter.Add(".txt");
picker.CurrentFolder = library.SaveFolder;
await picker.ShowAsync();
var file = picker.SelectedItem;
if (file != null)
{
await FileIO.WriteTextAsync(file, TheTextBox.Text);
}
}
private async void OnPlay(object sender, RoutedEventArgs e)
{
var text = TheTextBox.Text.ToString();
var stream = await _speechSynthesizer.SynthesizeTextToStreamAsync(text);
_mediaElement.SetSource(stream, stream.ContentType);
_mediaElement.AutoPlay = true;
_mediaElement.Play();
}
private void OnPauseResume(object sender, RoutedEventArgs e)
{
GazeKeyboard.IsEnabled = !GazeKeyboard.IsEnabled;
}
}
}

Просмотреть файл

@ -0,0 +1,54 @@
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp">
<Identity
Name="46799fa2-9a41-4ab8-817d-923ee9c0ceac"
Publisher="CN=harishsk"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="46799fa2-9a41-4ab8-817d-923ee9c0ceac" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>GazeInputTest</DisplayName>
<PublisherDisplayName>harishsk</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="GazeInputTest.App">
<uap:VisualElements
DisplayName="GazeInputTest"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png"
Description="GazeInputTest"
BackgroundColor="transparent">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<uap:Capability Name="documentsLibrary"/>
<uap:Capability Name="musicLibrary"/>
<uap:Capability Name="picturesLibrary"/>
<uap:Capability Name="videosLibrary"/>
<rescap:Capability Name="inputInjectionBrokered" />
<Capability Name="internetClient" />
<DeviceCapability Name="gazeInput" />
</Capabilities>
</Package>

Просмотреть файл

@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("GazeInputTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GazeInputTest")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
// [assembly: AssemblyVersion("1.0.0.0")]
// [assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

Просмотреть файл

@ -0,0 +1,26 @@
<!--
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
<Type Name="App1.MyClass" Dynamic="Required All"/>
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Application>
<!--
An Assembly element with Name="*Application*" applies to all assemblies in
the application package. The asterisks are not wildcards.
-->
<Assembly Name="*Application*" Dynamic="Required All" />
<!-- Add your application specific runtime directives here. -->
</Application>
</Directives>