[QuickAccent] Add description of current selected letter (#20587)

* Adding unicode names and adjusting UI (WIP)

* Added changing letter names

* Add optioins to hide description (WIP)

* WIP

* Change to binding property

* Adress PR comments

* Set TextBlock in border

* * Added to settings
* Fixed string showing/not showing one time after switching character
* Removed unneccessairy command in SettingsService.cs
* Moved showdescription enum to settings.ui

* Adding Fluent design :)

* Fix merge errors

* Center list

* Fixed code not working. Accepted some code style changes.

* Merge main in branch #2

* [Quick Accent] support unicode description for UTF-16 surrogate pairs

* [Quick Accent] fix check-spelling-bot errors

* [check-spelling] accept LANGID as correct word

* [Quick Accent] fix delay when calling ShowToolbar for the first time

* [Quick Accent] use toggle switch to turn off/on Unicode description

* [Quick Accent] fix after merge

* [Quick Accent] add UnicodeInformation.dll to installer

Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
Aaron Junker
2022-12-02 15:45:49 +01:00
committed by GitHub
parent eca77ad8b3
commit e731cc04c1
15 changed files with 635 additions and 662 deletions

View File

@@ -864,6 +864,7 @@ Kyrgyzstan
Kyzylorda
LAlt
Lambson
LANGID
langword
Lastdevice
Laute

View File

@@ -139,7 +139,7 @@
<?define HostsMicrosoftUIXamlAssetsInstallFiles=NoiseAsset_256x256_PNG.png?>
<?define PowerAccentFiles=ControlzEx.dll;Ijwhost.dll;MahApps.Metro.dll;Microsoft.Xaml.Behaviors.dll;PowerAccent.Core.dll;PowerAccent.deps.json;PowerAccent.dll;PowerAccent.exe;PowerAccent.runtimeconfig.json;PowerToys.PowerAccentModuleInterface.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerAccent.deps.json;PowerToys.PowerAccent.dll;PowerToys.PowerAccent.exe;PowerToys.PowerAccent.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;System.IO.Abstractions.dll;System.Management.dll;Vanara.Core.dll;Vanara.PInvoke.ComCtl32.dll;Vanara.PInvoke.Cryptography.dll;Vanara.PInvoke.Gdi32.dll;Vanara.PInvoke.Kernel32.dll;Vanara.PInvoke.Ole.dll;Vanara.PInvoke.Rpc.dll;Vanara.PInvoke.Security.dll;Vanara.PInvoke.Shared.dll;Vanara.PInvoke.Shell32.dll;Vanara.PInvoke.ShlwApi.dll;Vanara.PInvoke.User32.dll;PowerToys.PowerAccentKeyboardService.dll;Microsoft.Windows.SDK.NET.dll;WinRT.Runtime.dll;PowerToys.GPOWrapper.dll?>
<?define PowerAccentFiles=ControlzEx.dll;Ijwhost.dll;MahApps.Metro.dll;Microsoft.Xaml.Behaviors.dll;PowerAccent.Core.dll;PowerAccent.deps.json;PowerAccent.dll;PowerAccent.exe;PowerAccent.runtimeconfig.json;PowerToys.PowerAccentModuleInterface.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.PowerAccent.deps.json;PowerToys.PowerAccent.dll;PowerToys.PowerAccent.exe;PowerToys.PowerAccent.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;System.IO.Abstractions.dll;System.Management.dll;Vanara.Core.dll;Vanara.PInvoke.ComCtl32.dll;Vanara.PInvoke.Cryptography.dll;Vanara.PInvoke.Gdi32.dll;Vanara.PInvoke.Kernel32.dll;Vanara.PInvoke.Ole.dll;Vanara.PInvoke.Rpc.dll;Vanara.PInvoke.Security.dll;Vanara.PInvoke.Shared.dll;Vanara.PInvoke.Shell32.dll;Vanara.PInvoke.ShlwApi.dll;Vanara.PInvoke.User32.dll;PowerToys.PowerAccentKeyboardService.dll;Microsoft.Windows.SDK.NET.dll;WinRT.Runtime.dll;PowerToys.GPOWrapper.dll;UnicodeInformation.dll?>
<Product Id="*"
Name="PowerToys (Preview)"

File diff suppressed because it is too large Load Diff

View File

@@ -17,12 +17,14 @@
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
<PackageReference Include="UnicodeInformation" Version="2.6.0" />
<PackageReference Include="Vanara.PInvoke.User32" Version="3.4.11" />
<PackageReference Include="Vanara.PInvoke.Shell32" Version="3.4.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
<ProjectReference Include="..\PowerAccentKeyboardService\PowerAccentKeyboardService.vcxproj" />
</ItemGroup>

View File

@@ -2,6 +2,9 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
using System.Text;
using System.Unicode;
using System.Windows;
using PowerAccent.Core.Services;
using PowerAccent.Core.Tools;
@@ -13,20 +16,31 @@ public class PowerAccent : IDisposable
{
private readonly SettingsService _settingService;
// Keys that show a description (like dashes) when ShowCharacterInfoSetting is 1
private readonly LetterKey[] _letterKeysShowingDescription = new LetterKey[] { LetterKey.VK_O };
private bool _visible;
private string[] _characters = Array.Empty<string>();
private string[] _characterDescriptions = Array.Empty<string>();
private int _selectedIndex = -1;
private bool _showUnicodeDescription;
public LetterKey[] LetterKeysShowingDescription => _letterKeysShowingDescription;
public bool ShowUnicodeDescription => _showUnicodeDescription;
public string[] CharacterDescriptions => _characterDescriptions;
public event Action<bool, string[]> OnChangeDisplay;
public event Action<int, string> OnSelectCharacter;
private KeyboardListener _keyboardListener;
private readonly KeyboardListener _keyboardListener;
public PowerAccent()
{
LoadUnicodeInfoCache();
_keyboardListener = new KeyboardListener();
_keyboardListener.InitHook();
_settingService = new SettingsService(_keyboardListener);
@@ -34,6 +48,11 @@ public class PowerAccent : IDisposable
SetEvents();
}
private void LoadUnicodeInfoCache()
{
UnicodeInfo.GetCharInfo(0);
}
private void SetEvents()
{
_keyboardListener.SetShowToolbarEvent(new PowerToys.PowerAccentKeyboardService.ShowToolbar((LetterKey letterKey) =>
@@ -70,14 +89,79 @@ public class PowerAccent : IDisposable
{
_visible = true;
_characters = (WindowsFunctions.IsCapsLockState() || WindowsFunctions.IsShiftState()) ? ToUpper(Languages.GetDefaultLetterKey(letterKey, _settingService.SelectedLang)) : Languages.GetDefaultLetterKey(letterKey, _settingService.SelectedLang);
_characterDescriptions = GetCharacterDescriptions(_characters);
_showUnicodeDescription = _settingService.ShowUnicodeDescription;
Task.Delay(_settingService.InputTime).ContinueWith(
t =>
t =>
{
if (_visible)
{
if (_visible)
{
OnChangeDisplay?.Invoke(true, _characters);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
OnChangeDisplay?.Invoke(true, _characters);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
private string GetCharacterDescription(string character)
{
List<UnicodeCharInfo> unicodeList = new List<UnicodeCharInfo>();
foreach (var codePoint in character.AsCodePointEnumerable())
{
unicodeList.Add(UnicodeInfo.GetCharInfo(codePoint));
}
if (unicodeList.Count == 0)
{
return string.Empty;
}
var description = new StringBuilder();
if (unicodeList.Count == 1)
{
var unicode = unicodeList.First();
var charUnicodeNumber = unicode.CodePoint.ToString("X4", CultureInfo.InvariantCulture);
description.AppendFormat(CultureInfo.InvariantCulture, "(U+{0}) {1} ", charUnicodeNumber, unicode.Name);
return description.ToString();
}
var displayTextAndCodes = new StringBuilder();
var names = new StringBuilder();
foreach (var unicode in unicodeList)
{
var charUnicodeNumber = unicode.CodePoint.ToString("X4", CultureInfo.InvariantCulture);
if (displayTextAndCodes.Length > 0)
{
displayTextAndCodes.Append(" - ");
}
displayTextAndCodes.AppendFormat(CultureInfo.InvariantCulture, "{0}: (U+{1})", unicode.GetDisplayText(), charUnicodeNumber);
if (names.Length > 0)
{
names.Append(", ");
}
names.Append(unicode.Name);
}
description.Append(displayTextAndCodes);
description.Append(": ");
description.Append(names);
return description.ToString();
}
private string[] GetCharacterDescriptions(string[] characters)
{
string[] charInfoCollection = Array.Empty<string>();
foreach (string character in characters)
{
charInfoCollection = charInfoCollection.Append<string>(GetCharacterDescription(character)).ToArray<string>();
}
return charInfoCollection;
}
private void SendInputAndHideToolbar(InputType inputType)
@@ -212,14 +296,7 @@ public class PowerAccent : IDisposable
string[] result = new string[array.Length];
for (int i = 0; i < array.Length; i++)
{
if (array[i].Contains('ß'))
{
result[i] = "ẞ";
}
else
{
result[i] = array[i].ToUpper(System.Globalization.CultureInfo.InvariantCulture);
}
result[i] = array[i].Contains('ß') ? "ẞ" : array[i].ToUpper(System.Globalization.CultureInfo.InvariantCulture);
}
return result;

View File

@@ -10,6 +10,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using PowerToys.PowerAccentKeyboardService;
using System.IO.Abstractions;
using System.Text.Json;
using static Vanara.PInvoke.LANGID;
public class SettingsService
{
@@ -91,6 +92,8 @@ public class SettingsService
Position = Position.Center;
break;
}
ShowUnicodeDescription = settings.Properties.ShowUnicodeDescription;
}
}
catch (Exception ex)
@@ -175,6 +178,21 @@ public class SettingsService
_selectedLang = value;
}
}
private bool _showUnicodeDescription;
public bool ShowUnicodeDescription
{
get
{
return _showUnicodeDescription;
}
set
{
_showUnicodeDescription = value;
}
}
}
public enum Position

View File

@@ -17,9 +17,8 @@ namespace PowerAccent.UI
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "QuickAccent";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
_mutex = new Mutex(true, appName, out bool createdNew);
if (!createdNew)
{

View File

@@ -29,7 +29,9 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
<ProjectReference Include="..\PowerAccent.Core\PowerAccent.Core.csproj" />
<ProjectReference Include="..\PowerAccentKeyboardService\PowerAccentKeyboardService.vcxproj" />
</ItemGroup>

View File

@@ -3,72 +3,138 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PowerAccent"
xmlns:local="clr-namespace:PowerAccent.UI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="50"
Height="50"
Height="120"
MinWidth="600"
AllowsTransparency="True"
Background="Transparent"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
ResizeMode="NoResize"
ShowInTaskbar="False"
SizeToContent="WidthAndHeight"
Visibility="Collapsed"
WindowStyle="None"
mc:Ignorable="d">
<Grid>
<ListBox
x:Name="characters"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
BorderBrush="SlateGray"
<Window.Resources>
<DataTemplate x:Key="DefaultKeyTemplate">
<TextBlock
VerticalAlignment="Center"
FontSize="18"
Text="{Binding}"
TextAlignment="Center" />
</DataTemplate>
<DataTemplate x:Key="SelectedKeyTemplate">
<TextBlock
VerticalAlignment="Center"
FontSize="18"
Foreground="White"
Text="{Binding}"
TextAlignment="Center" />
</DataTemplate>
</Window.Resources>
<Grid Margin="24,24,24,24">
<Border
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="#F9F9F9"
BorderBrush="#B6B6B6"
BorderThickness="1"
IsHitTestVisible="False">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="False" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock
VerticalAlignment="Center"
FontSize="18"
Text="{Binding}"
TextAlignment="Center" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style x:Name="ItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border
x:Name="myBorder"
Margin="0"
Padding="0"
SnapsToDevicePixels="true"
Style="{DynamicResource borderContent}">
<ContentPresenter />
</Border>
<ControlTemplate.Resources>
<Style x:Key="borderContent" TargetType="Border">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="#ECECEC" />
<Setter Property="Width" Value="50" />
<Setter Property="Height" Value="50" />
</Style>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="myBorder" Property="Background" Value="White" />
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
CornerRadius="8">
<Border.Effect>
<DropShadowEffect
BlurRadius="32"
Opacity="0.28"
ShadowDepth="1" />
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox
x:Name="characters"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="Transparent"
IsHitTestVisible="False"
HorizontalAlignment="Center">
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultKeyTemplate}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid
Width="48"
Height="48"
Margin="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
SnapsToDevicePixels="true"
Style="{DynamicResource borderContent}">
<Rectangle
x:Name="SelectionIndicator"
Margin="7"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Fill="#005FB8"
RadiusX="4"
RadiusY="4"
Visibility="Collapsed" />
<ContentPresenter Margin="12" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="SelectionIndicator" Property="Visibility" Value="Visible" />
<Setter Property="ContentTemplate" Value="{StaticResource SelectedKeyTemplate}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
IsItemsHost="False"
Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<Grid
Grid.Row="1"
Visibility="{Binding CharacterNameVisibility, UpdateSourceTrigger=PropertyChanged}">
<Border
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#F3F3F3"
CornerRadius="0,0,8,8">
<TextBlock
x:Name="characterName"
Margin="8"
FontSize="12"
Foreground="#8D8D8D"
Text="(U+0000) A COOL LETTER NAME COMES HERE"
TextAlignment="Center" />
</Border>
<Rectangle
Height="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
Fill="#E5E5E5" />
</Grid>
</Grid>
</Border>
</Grid>
</Window>

View File

@@ -3,15 +3,39 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Unicode;
using System.Windows;
using PowerToys.PowerAccentKeyboardService;
using Point = PowerAccent.Core.Point;
using Size = PowerAccent.Core.Size;
namespace PowerAccent.UI;
public partial class Selector : Window, IDisposable
public partial class Selector : Window, IDisposable, INotifyPropertyChanged
{
private Core.PowerAccent _powerAccent = new Core.PowerAccent();
private readonly Core.PowerAccent _powerAccent = new ();
private Visibility _characterNameVisibility = Visibility.Visible;
public event PropertyChangedEventHandler PropertyChanged;
public Visibility CharacterNameVisibility
{
get
{
return _characterNameVisibility;
}
set
{
_characterNameVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CharacterNameVisibility)));
}
}
public Selector()
{
@@ -31,11 +55,16 @@ public partial class Selector : Window, IDisposable
private void PowerAccent_OnSelectionCharacter(int index, string character)
{
characters.SelectedIndex = index;
characterName.Text = _powerAccent.CharacterDescriptions[index];
}
private void PowerAccent_OnChangeDisplay(bool isActive, string[] chars)
{
CharacterNameVisibility = _powerAccent.ShowUnicodeDescription ? Visibility.Visible : Visibility.Collapsed;
this.Visibility = isActive ? Visibility.Visible : Visibility.Collapsed;
if (isActive)
{
characters.ItemsSource = chars;
@@ -52,7 +81,7 @@ public partial class Selector : Window, IDisposable
private void CenterWindow()
{
UpdateLayout();
Size window = new Size(((System.Windows.Controls.Panel)Application.Current.MainWindow.Content).ActualWidth, ((System.Windows.Controls.Panel)Application.Current.MainWindow.Content).ActualHeight);
Size window = new (((System.Windows.Controls.Panel)Application.Current.MainWindow.Content).ActualWidth, ((System.Windows.Controls.Panel)Application.Current.MainWindow.Content).ActualHeight);
Point position = _powerAccent.GetDisplayCoordinates(window);
this.Left = position.X;
this.Top = position.Y;

View File

@@ -17,11 +17,11 @@ namespace PowerAccent;
internal static class Program
{
private static readonly CancellationTokenSource _tokenSource = new ();
private const string PROGRAM_NAME = "QuickAccent";
private const string PROGRAM_APP_NAME = "PowerToys.PowerAccent";
private static App _application;
private static int _powerToysRunnerPid;
private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
[STAThread]
public static void Main(string[] args)
@@ -55,7 +55,7 @@ internal static class Program
Task.Run(
() =>
{
EventWaitHandle eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.PowerAccentExitEvent());
EventWaitHandle eventHandle = new (false, EventResetMode.AutoReset, Constants.PowerAccentExitEvent());
if (eventHandle.WaitOne())
{
Terminate();

View File

@@ -24,6 +24,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("excluded_apps")]
public StringProperty ExcludedApps { get; set; }
[JsonPropertyName("show_description")]
public bool ShowUnicodeDescription { get; set; }
public PowerAccentProperties()
{
ActivationKey = PowerAccentActivationKey.Both;
@@ -31,6 +34,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
InputTime = new IntProperty(200);
SelectedLang = "ALL";
ExcludedApps = new StringProperty();
ShowUnicodeDescription = false;
}
}
}

View File

@@ -2525,6 +2525,9 @@ Activate by holding the key for the character you want to add an accent to, then
<value>The continuous capture mode will consume more resources when in use. Also, measurements will be excluded from screenshots and screen capture.</value>
<comment>pointer as in mouse pointer. Resources refer to things like CPU, GPU, RAM</comment>
</data>
<data name="QuickAccent_Description_Indicator.Header" xml:space="preserve">
<value>Show the Unicode code and name of the currently selected character</value>
</data>
<data name="QuickAccent_DisableFullscreen.Header" xml:space="preserve">
<value>Disable when Game Mode is On</value>
</data>

View File

@@ -237,6 +237,24 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool ShowUnicodeDescription
{
get
{
return _powerAccentSettings.Properties.ShowUnicodeDescription;
}
set
{
if (value != _powerAccentSettings.Properties.ShowUnicodeDescription)
{
_powerAccentSettings.Properties.ShowUnicodeDescription = value;
OnPropertyChanged(nameof(ShowUnicodeDescription));
RaisePropertyChanged();
}
}
}
private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
// Notify UI of property change

View File

@@ -110,6 +110,9 @@
<ComboBoxItem x:Uid="QuickAccent_ToolbarPosition_Center" />
</ComboBox>
</labs:SettingsCard>
<labs:SettingsCard x:Uid="QuickAccent_Description_Indicator" HeaderIcon="{ui:FontIcon FontFamily={StaticResource SymbolThemeFontFamily}, Glyph=&#xE946;}">
<ToggleSwitch x:Uid="QuickAccent_UnicodeDescription_ToggleSwitch" IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.ShowUnicodeDescription}" />
</labs:SettingsCard>
</controls:SettingsGroup>
<controls:SettingsGroup