diff --git a/src/modules/registrypreview/RegistryPreviewUILib/ClipboardHelper.cs b/src/modules/registrypreview/RegistryPreviewUILib/ClipboardHelper.cs new file mode 100644 index 000000000000..7df10de2fac3 --- /dev/null +++ b/src/modules/registrypreview/RegistryPreviewUILib/ClipboardHelper.cs @@ -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 +{ + /// + /// Helper class to centralize clipboard actions + /// + internal static class ClipboardHelper + { + internal static void CopyToClipboardAction(string text) + { + try + { + var data = new DataPackage(); + data.SetText(text); + Clipboard.SetContent(data); + Clipboard.Flush(); + } + catch + { + } + } + } +} diff --git a/src/modules/registrypreview/RegistryPreviewUILib/RegistryKey.xaml.cs b/src/modules/registrypreview/RegistryPreviewUILib/RegistryKey.xaml.cs index 44660000592f..6a190bcdb2b4 100644 --- a/src/modules/registrypreview/RegistryPreviewUILib/RegistryKey.xaml.cs +++ b/src/modules/registrypreview/RegistryPreviewUILib/RegistryKey.xaml.cs @@ -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 { /// @@ -28,5 +32,19 @@ public RegistryKey(string name, string fullPath, string image, string toolTipTex 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); + } } } diff --git a/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.Utilities.cs b/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.Utilities.cs index b3073669f7b7..b8fc6e4e1d9a 100644 --- a/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.Utilities.cs +++ b/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.Utilities.cs @@ -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 @@ private bool ParseRegistryFile(string filenameText) registryLine = StripFirstAndLast(registryLine); treeViewNode = AddTextToTree(registryLine, imageName); + lastKeyPath = registryLine; } else if (registryLine.StartsWith('"') && registryLine.EndsWith("=-", StringComparison.InvariantCulture)) { @@ -271,7 +273,7 @@ private bool ParseRegistryFile(string filenameText) 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 @@ private bool ParseRegistryFile(string filenameText) 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 @@ private bool ParseRegistryFile(string filenameText) 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 { diff --git a/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml b/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml index 058663459ec4..a48222e9aa8f 100644 --- a/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml +++ b/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml @@ -167,6 +167,12 @@ IsTabStop="False" Orientation="Horizontal" Spacing="8"> + + + + + + + + + + + + + + - + + + + + + IsReadOnly="True"> + + + + + + + + + + + + + + + + diff --git a/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml.cs b/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml.cs index 1687a24293d3..06e435c9f0e4 100644 --- a/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml.cs +++ b/src/modules/registrypreview/RegistryPreviewUILib/RegistryPreviewMainPage.xaml.cs @@ -8,6 +8,7 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.Windows.ApplicationModel.Resources; +using Windows.ApplicationModel.DataTransfer; namespace RegistryPreviewUILib { diff --git a/src/modules/registrypreview/RegistryPreviewUILib/RegistryValue.xaml.cs b/src/modules/registrypreview/RegistryPreviewUILib/RegistryValue.xaml.cs index 3e0d16c9328f..1bf403c3fab1 100644 --- a/src/modules/registrypreview/RegistryPreviewUILib/RegistryValue.xaml.cs +++ b/src/modules/registrypreview/RegistryPreviewUILib/RegistryValue.xaml.cs @@ -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 @@ public class RegistryValue 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 @@ public Uri ImageUri } } - 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); } } } diff --git a/src/modules/registrypreview/RegistryPreviewUILib/Strings/en-US/Resources.resw b/src/modules/registrypreview/RegistryPreviewUILib/Strings/en-US/Resources.resw index 580d108d9a7b..9401908d216e 100644 --- a/src/modules/registrypreview/RegistryPreviewUILib/Strings/en-US/Resources.resw +++ b/src/modules/registrypreview/RegistryPreviewUILib/Strings/en-US/Resources.resw @@ -257,4 +257,28 @@ (zero-length binary value) + + Copy path + Like "Copy item" + + + Copy name + Like "Copy item" + + + Copy type + Like "Copy item" + + + Copy data + Like "Copy item" + + + Copy value + Like "Copy item" + + + Copy value with key path + Like "Copy item" + \ No newline at end of file