[RegistryPreview]Copy context menu, data tooltip, MULTI_SZ fix (#36631)

* add context menus

* string resources for contextmenu

* fix line break parsing for MULTI_SZ

* better presentation of multiline values and value tooltip

* cleanup
This commit is contained in:
Heiko 2025-01-17 15:53:20 +01:00 коммит произвёл GitHub
Родитель e7abd34778
Коммит 44f170d4ed
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
7 изменённых файлов: 184 добавлений и 19 удалений

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

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation
// 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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
namespace RegistryPreviewUILib
{
/// <summary>
/// Helper class to centralize clipboard actions
/// </summary>
internal static class ClipboardHelper
{
internal static void CopyToClipboardAction(string text)
{
try
{
var data = new DataPackage();
data.SetText(text);
Clipboard.SetContent(data);
Clipboard.Flush();
}
catch
{
}
}
}
}

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

@ -2,6 +2,10 @@
// 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.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using Windows.ApplicationModel.DataTransfer;
namespace RegistryPreviewUILib
{
/// <summary>
@ -28,5 +32,19 @@ namespace RegistryPreviewUILib
this.Image = image;
this.ToolTipText = toolTipText;
}
public ICommand CopyToClipboardName_Click => new RelayCommand(CopyToClipboardName);
public ICommand CopyToClipboardKeyPath_Click => new RelayCommand(CopyToClipboardKeyPath);
private void CopyToClipboardName()
{
ClipboardHelper.CopyToClipboardAction(Name);
}
private void CopyToClipboardKeyPath()
{
ClipboardHelper.CopyToClipboardAction(FullPath);
}
}
}

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

@ -23,6 +23,7 @@ namespace RegistryPreviewUILib
public sealed partial class RegistryPreviewMainPage : Page
{
private static SemaphoreSlim _dialogSemaphore = new(1);
private string lastKeyPath;
public delegate void UpdateWindowTitleFunction(string title);
@ -261,6 +262,7 @@ namespace RegistryPreviewUILib
registryLine = StripFirstAndLast(registryLine);
treeViewNode = AddTextToTree(registryLine, imageName);
lastKeyPath = registryLine;
}
else if (registryLine.StartsWith('"') && registryLine.EndsWith("=-", StringComparison.InvariantCulture))
{
@ -271,7 +273,7 @@ namespace RegistryPreviewUILib
registryLine = StripFirstAndLast(registryLine);
// Create a new listview item that will be used to display the delete value and store it
registryValue = new RegistryValue(registryLine, string.Empty, string.Empty);
registryValue = new RegistryValue(registryLine, string.Empty, string.Empty, lastKeyPath);
SetValueToolTip(registryValue);
// store the ListViewItem, if we have a valid Key to attach to
@ -310,7 +312,7 @@ namespace RegistryPreviewUILib
value = value.Trim();
// Create a new listview item that will be used to display the value
registryValue = new RegistryValue(name, "REG_SZ", string.Empty);
registryValue = new RegistryValue(name, "REG_SZ", string.Empty, lastKeyPath);
// if the first character is a " then this is a string value, so find the last most " which will avoid comments
if (value.StartsWith('"'))
@ -553,19 +555,10 @@ namespace RegistryPreviewUILib
var bytes = value.Split(',').Select(
c => c.Length == 2 ? byte.Parse(c, NumberStyles.HexNumber, CultureInfo.InvariantCulture) : throw null).ToArray();
if (registryValue.Type == "REG_MULTI_SZ")
{
// Replace zeros (00,00) with spaces
for (int i = 0; i < bytes.Length; i += 2)
{
if (bytes[i] == 0 && bytes[i + 1] == 0)
{
bytes[i] = 0x20;
}
}
}
value = Encoding.Unicode.GetString(bytes);
// Correctly format line breaks and remove trailing line breaks. (GitHub PowerToys #36629)
value = value.Replace('\0', '\r').TrimEnd('\r');
}
catch
{

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

@ -167,6 +167,12 @@
IsTabStop="False"
Orientation="Horizontal"
Spacing="8">
<StackPanel.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="ContextMenu_CopyName" Command="{Binding Content.CopyToClipboardName_Click}" />
<MenuFlyoutItem x:Uid="ContextMenu_CopyKeyPath" Command="{Binding Content.CopyToClipboardKeyPath_Click}" />
</MenuFlyout>
</StackPanel.ContextFlyout>
<Image
MaxWidth="16"
MaxHeight="16"
@ -208,6 +214,14 @@
VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="8">
<StackPanel.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="ContextMenu_CopyName" Command="{Binding CopyToClipboardName_Click}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="ContextMenu_CopyValue" Command="{Binding CopyToClipboardEntry_Click}" />
<MenuFlyoutItem x:Uid="ContextMenu_CopyValueWithPath" Command="{Binding CopyToClipboardWithPath_Click}" />
</MenuFlyout>
</StackPanel.ContextFlyout>
<Image
MaxWidth="16"
MaxHeight="16"
@ -226,12 +240,49 @@
x:Uid="TypeColumn"
Width="Auto"
Binding="{Binding Type}"
FontSize="{StaticResource CaptionTextBlockFontSize}" />
<tk7controls:DataGridTextColumn
FontSize="{StaticResource CaptionTextBlockFontSize}">
<tk7controls:DataGridTextColumn.CellStyle>
<Style TargetType="tk7controls:DataGridCell">
<Setter Property="ContextFlyout">
<Setter.Value>
<MenuFlyout>
<MenuFlyoutItem x:Uid="ContextMenu_CopyType" Command="{Binding CopyToClipboardType_Click}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="ContextMenu_CopyValue" Command="{Binding CopyToClipboardEntry_Click}" />
<MenuFlyoutItem x:Uid="ContextMenu_CopyValueWithPath" Command="{Binding CopyToClipboardWithPath_Click}" />
</MenuFlyout>
</Setter.Value>
</Setter>
</Style>
</tk7controls:DataGridTextColumn.CellStyle>
</tk7controls:DataGridTextColumn>
<tk7controls:DataGridTemplateColumn
x:Uid="ValueColumn"
Width="Auto"
Binding="{Binding Value}"
FontSize="{StaticResource CaptionTextBlockFontSize}" />
IsReadOnly="True">
<tk7controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel
Margin="4"
VerticalAlignment="Center"
Orientation="Horizontal">
<StackPanel.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem x:Uid="ContextMenu_CopyData" Command="{Binding CopyToClipboardData_Click}" />
<MenuFlyoutSeparator />
<MenuFlyoutItem x:Uid="ContextMenu_CopyValue" Command="{Binding CopyToClipboardEntry_Click}" />
<MenuFlyoutItem x:Uid="ContextMenu_CopyValueWithPath" Command="{Binding CopyToClipboardWithPath_Click}" />
</MenuFlyout>
</StackPanel.ContextFlyout>
<TextBlock
IsTabStop="False"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{Binding ValueOneLine}"
ToolTipService.ToolTip="{Binding Value}" />
</StackPanel>
</DataTemplate>
</tk7controls:DataGridTemplateColumn.CellTemplate>
</tk7controls:DataGridTemplateColumn>
</tk7controls:DataGrid.Columns>
</tk7controls:DataGrid>
</Border>

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

@ -8,6 +8,7 @@ using System.IO;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Windows.ApplicationModel.Resources;
using Windows.ApplicationModel.DataTransfer;
namespace RegistryPreviewUILib
{

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

@ -3,6 +3,10 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml;
using Windows.ApplicationModel.DataTransfer;
namespace RegistryPreviewUILib
{
@ -17,12 +21,16 @@ namespace RegistryPreviewUILib
private static Uri uriDeleteValue = new Uri("ms-appx:///Assets/RegistryPreview/deleted-value32.png");
private static Uri uriErrorValue = new Uri("ms-appx:///Assets/RegistryPreview/error32.png");
public string Key { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public string ValueOneLine => Value.Replace('\r', ' ');
public string ToolTipText { get; set; }
public Uri ImageUri
@ -46,12 +54,49 @@ namespace RegistryPreviewUILib
}
}
public RegistryValue(string name, string type, string value)
public RegistryValue(string name, string type, string value, string key)
{
this.Name = name;
this.Type = type;
this.Value = value;
this.ToolTipText = string.Empty;
this.Key = key;
}
// Commands
public ICommand CopyToClipboardEntry_Click => new RelayCommand(CopyToClipboardEntry);
public ICommand CopyToClipboardWithPath_Click => new RelayCommand(CopyToClipboardEntryWithPath);
public ICommand CopyToClipboardName_Click => new RelayCommand(CopyToClipboardName);
public ICommand CopyToClipboardType_Click => new RelayCommand(CopyToClipboardType);
public ICommand CopyToClipboardData_Click => new RelayCommand(CopyToClipboardData);
private void CopyToClipboardEntry()
{
ClipboardHelper.CopyToClipboardAction($"{Name}\r\n{Type}\r\n{Value}");
}
private void CopyToClipboardEntryWithPath()
{
ClipboardHelper.CopyToClipboardAction($"{Key}\r\n{Name}\r\n{Type}\r\n{Value}");
}
private void CopyToClipboardName()
{
ClipboardHelper.CopyToClipboardAction(Name);
}
private void CopyToClipboardType()
{
ClipboardHelper.CopyToClipboardAction(Type);
}
private void CopyToClipboardData()
{
ClipboardHelper.CopyToClipboardAction(Value);
}
}
}

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

@ -257,4 +257,28 @@
<data name="ZeroLength" xml:space="preserve">
<value>(zero-length binary value)</value>
</data>
<data name="ContextMenu_CopyKeyPath.Text" xml:space="preserve">
<value>Copy path</value>
<comment>Like "Copy item"</comment>
</data>
<data name="ContextMenu_CopyName.Text" xml:space="preserve">
<value>Copy name</value>
<comment>Like "Copy item"</comment>
</data>
<data name="ContextMenu_CopyType.Text" xml:space="preserve">
<value>Copy type</value>
<comment>Like "Copy item"</comment>
</data>
<data name="ContextMenu_CopyData.Text" xml:space="preserve">
<value>Copy data</value>
<comment>Like "Copy item"</comment>
</data>
<data name="ContextMenu_CopyValue.Text" xml:space="preserve">
<value>Copy value</value>
<comment>Like "Copy item"</comment>
</data>
<data name="ContextMenu_CopyValueWithPath.Text" xml:space="preserve">
<value>Copy value with key path</value>
<comment>Like "Copy item"</comment>
</data>
</root>