diff --git a/Cpp.Build.props b/Cpp.Build.props index f146a4d770..7b988f0d6f 100644 --- a/Cpp.Build.props +++ b/Cpp.Build.props @@ -42,6 +42,11 @@ + + true + TurnOffAllWarnings + true + true Use pch.h @@ -111,13 +116,11 @@ - + true true - + false true false diff --git a/Directory.Build.targets b/Directory.Build.targets index 6da66bc8a8..f815cfbb3f 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -8,4 +8,20 @@ $(WindowsSdkDir)bin\x64\mt.exe + + + + + + + + \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 60567e30b8..eb04903b7e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,6 +7,8 @@ + + @@ -70,10 +72,12 @@ This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail. --> + - - - + + + + @@ -112,6 +116,7 @@ + diff --git a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs index 17b8139bad..1f7829a0bd 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste.UnitTests/ServicesTests/AIServiceBatchIntegrationTests.cs @@ -144,7 +144,7 @@ public sealed class AIServiceBatchIntegrationTests switch (format) { case PasteFormats.CustomTextTransformation: - var transformResult = await services.CustomActionTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress); + var transformResult = await services.CustomActionTransformService.TransformAsync(batchTestInput.Prompt, batchTestInput.Clipboard, null, CancellationToken.None, progress); return DataPackageHelpers.CreateFromText(transformResult.Content ?? string.Empty); case PasteFormats.KernelQuery: diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Helpers/DataPackageHelpers.cs b/src/modules/AdvancedPaste/AdvancedPaste/Helpers/DataPackageHelpers.cs index 2cd7554a50..f5439aecf1 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Helpers/DataPackageHelpers.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Helpers/DataPackageHelpers.cs @@ -225,6 +225,24 @@ internal static class DataPackageHelpers internal static async Task GetHtmlContentAsync(this DataPackageView dataPackageView) => dataPackageView.Contains(StandardDataFormats.Html) ? await dataPackageView.GetHtmlFormatAsync() : string.Empty; + internal static async Task GetImageAsPngBytesAsync(this DataPackageView dataPackageView) + { + var bitmap = await dataPackageView.GetImageContentAsync(); + if (bitmap == null) + { + return null; + } + + using var pngStream = new InMemoryRandomAccessStream(); + var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, pngStream); + encoder.SetSoftwareBitmap(bitmap); + await encoder.FlushAsync(); + + using var memoryStream = new MemoryStream(); + await pngStream.AsStreamForRead().CopyToAsync(memoryStream); + return memoryStream.ToArray(); + } + internal static async Task GetImageContentAsync(this DataPackageView dataPackageView) { using var stream = await dataPackageView.GetImageStreamAsync(); diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Helpers/NativeMethods.cs b/src/modules/AdvancedPaste/AdvancedPaste/Helpers/NativeMethods.cs index 6e53e9b618..08293d4be0 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Helpers/NativeMethods.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Helpers/NativeMethods.cs @@ -166,5 +166,8 @@ namespace AdvancedPaste.Helpers [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern HResult AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern uint GetClipboardSequenceNumber(); } } diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Models/PasteFormats.cs b/src/modules/AdvancedPaste/AdvancedPaste/Models/PasteFormats.cs index 99243ebb5e..1479912e66 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Models/PasteFormats.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Models/PasteFormats.cs @@ -46,7 +46,7 @@ public enum PasteFormats CanPreview = true, SupportedClipboardFormats = ClipboardFormat.Image, IPCKey = AdvancedPasteAdditionalActions.PropertyNames.ImageToText, - KernelFunctionDescription = "Takes an image in the clipboard and extracts all text from it using OCR.")] + KernelFunctionDescription = "Takes an image from the clipboard and extracts text using OCR. This function is intended only for explicit text extraction or OCR requests.")] ImageToText, [PasteFormatMetadata( @@ -118,8 +118,8 @@ public enum PasteFormats IconGlyph = "\uE945", RequiresAIService = true, CanPreview = true, - SupportedClipboardFormats = ClipboardFormat.Text, - KernelFunctionDescription = "Takes input instructions and transforms clipboard text (not TXT files) with these input instructions, putting the result back on the clipboard. This uses AI to accomplish the task.", + SupportedClipboardFormats = ClipboardFormat.Text | ClipboardFormat.Image, + KernelFunctionDescription = "Takes user instructions and applies them to the current clipboard content (text or image). Use this function for image analysis, description, or transformation tasks beyond simple OCR.", RequiresPrompt = true)] CustomTextTransformation, } diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/CustomActionTransformService.cs b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/CustomActionTransformService.cs index 57d55492a4..05cdcbe81f 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/CustomActionTransformService.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/CustomActionTransformService.cs @@ -40,15 +40,15 @@ namespace AdvancedPaste.Services.CustomActions this.userSettings = userSettings; } - public async Task TransformTextAsync(string prompt, string inputText, CancellationToken cancellationToken, IProgress progress) + public async Task TransformAsync(string prompt, string inputText, byte[] imageBytes, CancellationToken cancellationToken, IProgress progress) { var pasteConfig = userSettings?.PasteAIConfiguration; var providerConfig = BuildProviderConfig(pasteConfig); - return await TransformAsync(prompt, inputText, providerConfig, cancellationToken, progress); + return await TransformAsync(prompt, inputText, imageBytes, providerConfig, cancellationToken, progress); } - private async Task TransformAsync(string prompt, string inputText, PasteAIConfig providerConfig, CancellationToken cancellationToken, IProgress progress) + private async Task TransformAsync(string prompt, string inputText, byte[] imageBytes, PasteAIConfig providerConfig, CancellationToken cancellationToken, IProgress progress) { ArgumentNullException.ThrowIfNull(providerConfig); @@ -57,9 +57,9 @@ namespace AdvancedPaste.Services.CustomActions return new CustomActionTransformResult(string.Empty, AIServiceUsage.None); } - if (string.IsNullOrWhiteSpace(inputText)) + if (string.IsNullOrWhiteSpace(inputText) && imageBytes is null) { - Logger.LogWarning("Clipboard has no usable text data"); + Logger.LogWarning("Clipboard has no usable data"); return new CustomActionTransformResult(string.Empty, AIServiceUsage.None); } @@ -80,6 +80,8 @@ namespace AdvancedPaste.Services.CustomActions { Prompt = prompt, InputText = inputText, + ImageBytes = imageBytes, + ImageMimeType = imageBytes != null ? "image/png" : null, SystemPrompt = systemPrompt, }; diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/ICustomActionTransformService.cs b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/ICustomActionTransformService.cs index 1c3ecb980c..564db3fdc5 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/ICustomActionTransformService.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/ICustomActionTransformService.cs @@ -12,6 +12,6 @@ namespace AdvancedPaste.Services.CustomActions { public interface ICustomActionTransformService { - Task TransformTextAsync(string prompt, string inputText, CancellationToken cancellationToken, IProgress progress); + Task TransformAsync(string prompt, string inputText, byte[] imageBytes, CancellationToken cancellationToken, IProgress progress); } } diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/PasteAIRequest.cs b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/PasteAIRequest.cs index 0e15c93e05..96dabbfa05 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/PasteAIRequest.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/PasteAIRequest.cs @@ -12,6 +12,10 @@ namespace AdvancedPaste.Services.CustomActions public string InputText { get; init; } + public byte[] ImageBytes { get; init; } + + public string ImageMimeType { get; init; } + public string SystemPrompt { get; init; } public AIServiceUsage Usage { get; set; } = AIServiceUsage.None; diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/SemanticKernelPasteProvider.cs b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/SemanticKernelPasteProvider.cs index eb2f56e01f..636d2e3e78 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/SemanticKernelPasteProvider.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Services/CustomActions/SemanticKernelPasteProvider.cs @@ -64,21 +64,13 @@ namespace AdvancedPaste.Services.CustomActions var prompt = request.Prompt; var inputText = request.InputText; - if (string.IsNullOrWhiteSpace(prompt) || string.IsNullOrWhiteSpace(inputText)) + var imageBytes = request.ImageBytes; + + if (string.IsNullOrWhiteSpace(prompt) || (string.IsNullOrWhiteSpace(inputText) && imageBytes is null)) { - throw new ArgumentException("Prompt and input text must be provided", nameof(request)); + throw new ArgumentException("Prompt and input content must be provided", nameof(request)); } - var userMessageContent = $""" - User instructions: - {prompt} - - Clipboard Content: - {inputText} - - Output: - """; - var executionSettings = CreateExecutionSettings(); var kernel = CreateKernel(); var modelId = _config.Model; @@ -102,7 +94,32 @@ namespace AdvancedPaste.Services.CustomActions var chatHistory = new ChatHistory(); chatHistory.AddSystemMessage(systemPrompt); - chatHistory.AddUserMessage(userMessageContent); + + if (imageBytes != null) + { + var collection = new ChatMessageContentItemCollection(); + if (!string.IsNullOrWhiteSpace(inputText)) + { + collection.Add(new TextContent($"Clipboard Content:\n{inputText}")); + } + + collection.Add(new ImageContent(imageBytes, request.ImageMimeType ?? "image/png")); + collection.Add(new TextContent($"User instructions:\n{prompt}\n\nOutput:")); + chatHistory.AddUserMessage(collection); + } + else + { + var userMessageContent = $""" + User instructions: + {prompt} + + Clipboard Content: + {inputText} + + Output: + """; + chatHistory.AddUserMessage(userMessageContent); + } var response = await chatService.GetChatMessageContentAsync(chatHistory, executionSettings, kernel, cancellationToken); chatHistory.Add(response); diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Services/KernelServiceBase.cs b/src/modules/AdvancedPaste/AdvancedPaste/Services/KernelServiceBase.cs index 47e208eb49..0d753d1ec3 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Services/KernelServiceBase.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Services/KernelServiceBase.cs @@ -67,12 +67,36 @@ public abstract class KernelServiceBase( LogResult(cacheUsed, isSavedQuery, kernel.GetOrAddActionChain(), usage); + var outputPackage = kernel.GetDataPackage(); + var hasUsableData = await outputPackage.GetView().HasUsableDataAsync(); + if (kernel.GetLastError() is Exception ex) { - throw ex; + // If we have an error, but the AI provided a final text response, we can ignore the error (likely a tool failure that the AI handled). + // However, if we have usable data (e.g. from a successful tool call before the error?), we might want to keep it? + // In the case of ImageToText failure, outputPackage is empty (new DataPackage), hasUsableData is false. + // So we check if there is a valid response in the chat history. + var lastMessage = chatHistory.LastOrDefault(); + bool hasAssistantResponse = lastMessage != null && lastMessage.Role == AuthorRole.Assistant && !string.IsNullOrEmpty(lastMessage.Content); + + if (!hasAssistantResponse && !hasUsableData) + { + throw ex; + } + + // If we have a response or data, we log the error but proceed. + Logger.LogWarning($"Kernel operation encountered an error but proceeded with available response/data: {ex.Message}"); } - var outputPackage = kernel.GetDataPackage(); + if (!hasUsableData) + { + var lastMessage = chatHistory.LastOrDefault(); + if (lastMessage != null && lastMessage.Role == AuthorRole.Assistant && !string.IsNullOrEmpty(lastMessage.Content)) + { + outputPackage = DataPackageHelpers.CreateFromText(lastMessage.Content); + kernel.SetDataPackage(outputPackage); + } + } if (!(await outputPackage.GetView().HasUsableDataAsync())) { @@ -148,7 +172,21 @@ public abstract class KernelServiceBase( var systemPrompt = string.IsNullOrWhiteSpace(runtimeConfig.SystemPrompt) ? DefaultSystemPrompt : runtimeConfig.SystemPrompt; chatHistory.AddSystemMessage(systemPrompt); chatHistory.AddSystemMessage($"Available clipboard formats: {await kernel.GetDataFormatsAsync()}"); - chatHistory.AddUserMessage(prompt); + + var imageBytes = await kernel.GetDataPackageView().GetImageAsPngBytesAsync(); + if (imageBytes != null) + { + var collection = new ChatMessageContentItemCollection + { + new TextContent(prompt), + new ImageContent(imageBytes, "image/png"), + }; + chatHistory.AddUserMessage(collection); + } + else + { + chatHistory.AddUserMessage(prompt); + } if (ShouldModerateAdvancedAI()) { @@ -302,8 +340,16 @@ public abstract class KernelServiceBase( new ActionChainItem(PasteFormats.CustomTextTransformation, Arguments: new() { { PromptParameterName, fixedPrompt } }), async dataPackageView => { - var input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken()); - var result = await _customActionTransformService.TransformTextAsync(fixedPrompt, input, kernel.GetCancellationToken(), kernel.GetProgress()); + var imageBytes = await dataPackageView.GetImageAsPngBytesAsync(); + var input = await dataPackageView.GetTextOrHtmlTextAsync(); + + if (string.IsNullOrEmpty(input) && imageBytes == null) + { + // If we have no text and no image, try to get text via OCR or throw if nothing exists + input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken()); + } + + var result = await _customActionTransformService.TransformAsync(fixedPrompt, input, imageBytes, kernel.GetCancellationToken(), kernel.GetProgress()); return DataPackageHelpers.CreateFromText(result?.Content ?? string.Empty); }); @@ -313,15 +359,22 @@ public abstract class KernelServiceBase( new ActionChainItem(format, Arguments: new() { { PromptParameterName, prompt } }), async dataPackageView => { - var input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken()); - string output = await GetPromptBasedOutput(format, prompt, input, kernel.GetCancellationToken(), kernel.GetProgress()); + var imageBytes = await dataPackageView.GetImageAsPngBytesAsync(); + var input = await dataPackageView.GetTextOrHtmlTextAsync(); + + if (string.IsNullOrEmpty(input) && imageBytes == null) + { + input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken()); + } + + string output = await GetPromptBasedOutput(format, prompt, input, imageBytes, kernel.GetCancellationToken(), kernel.GetProgress()); return DataPackageHelpers.CreateFromText(output); }); - private async Task GetPromptBasedOutput(PasteFormats format, string prompt, string input, CancellationToken cancellationToken, IProgress progress) => + private async Task GetPromptBasedOutput(PasteFormats format, string prompt, string input, byte[] imageBytes, CancellationToken cancellationToken, IProgress progress) => format switch { - PasteFormats.CustomTextTransformation => (await _customActionTransformService.TransformTextAsync(prompt, input, cancellationToken, progress))?.Content ?? string.Empty, + PasteFormats.CustomTextTransformation => (await _customActionTransformService.TransformAsync(prompt, input, imageBytes, cancellationToken, progress))?.Content ?? string.Empty, _ => throw new ArgumentException($"Unsupported format {format} for prompt transform", nameof(format)), }; diff --git a/src/modules/AdvancedPaste/AdvancedPaste/Services/PasteFormatExecutor.cs b/src/modules/AdvancedPaste/AdvancedPaste/Services/PasteFormatExecutor.cs index aef9e39bb9..ff64a5ad83 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/Services/PasteFormatExecutor.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/Services/PasteFormatExecutor.cs @@ -37,7 +37,7 @@ public sealed class PasteFormatExecutor(IKernelService kernelService, ICustomAct pasteFormat.Format switch { PasteFormats.KernelQuery => await _kernelService.TransformClipboardAsync(pasteFormat.Prompt, clipboardData, pasteFormat.IsSavedQuery, cancellationToken, progress), - PasteFormats.CustomTextTransformation => DataPackageHelpers.CreateFromText((await _customActionTransformService.TransformTextAsync(pasteFormat.Prompt, await clipboardData.GetClipboardTextOrThrowAsync(cancellationToken), cancellationToken, progress))?.Content ?? string.Empty), + PasteFormats.CustomTextTransformation => DataPackageHelpers.CreateFromText((await _customActionTransformService.TransformAsync(pasteFormat.Prompt, await clipboardData.GetTextOrHtmlTextAsync(), await clipboardData.GetImageAsPngBytesAsync(), cancellationToken, progress))?.Content ?? string.Empty), _ => await TransformHelpers.TransformAsync(format, clipboardData, cancellationToken, progress), }); } diff --git a/src/modules/AdvancedPaste/AdvancedPaste/ViewModels/OptionsViewModel.cs b/src/modules/AdvancedPaste/AdvancedPaste/ViewModels/OptionsViewModel.cs index 8edd9b76ad..b055d46457 100644 --- a/src/modules/AdvancedPaste/AdvancedPaste/ViewModels/OptionsViewModel.cs +++ b/src/modules/AdvancedPaste/AdvancedPaste/ViewModels/OptionsViewModel.cs @@ -45,6 +45,7 @@ namespace AdvancedPaste.ViewModels private CancellationTokenSource _pasteActionCancellationTokenSource; private string _currentClipboardHistoryId; + private uint _lastClipboardSequenceNumber; private DateTimeOffset? _currentClipboardTimestamp; private ClipboardFormat _lastClipboardFormats = ClipboardFormat.None; private bool _clipboardHistoryUnavailableLogged; @@ -455,6 +456,7 @@ namespace AdvancedPaste.ViewModels { ResetClipboardPreview(); _currentClipboardHistoryId = null; + _lastClipboardSequenceNumber = 0; _currentClipboardTimestamp = null; _lastClipboardFormats = ClipboardFormat.None; return; @@ -477,6 +479,13 @@ namespace AdvancedPaste.ViewModels { bool clipboardChanged = formatsChanged; + var currentSequenceNumber = NativeMethods.GetClipboardSequenceNumber(); + if (_lastClipboardSequenceNumber != currentSequenceNumber) + { + clipboardChanged = true; + _lastClipboardSequenceNumber = currentSequenceNumber; + } + if (Clipboard.IsHistoryEnabled()) { try diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp index c7d22d474f..64caaa115f 100644 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp +++ b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp @@ -312,13 +312,39 @@ private: return false; } - void read_settings(PowerToysSettings::PowerToyValues& settings) + void read_settings(PowerToysSettings::PowerToyValues& settings) { const auto settingsObject = settings.get_raw_json(); // Migrate Paste As Plain text shortcut Hotkey old_paste_as_plain_hotkey; bool old_data_migrated = migrate_data_and_remove_data_file(old_paste_as_plain_hotkey); + + if (settingsObject.GetView().Size()) + { + const auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES); + + m_is_advanced_ai_enabled = has_advanced_ai_provider(propertiesObject); + + if (propertiesObject.HasKey(JSON_KEY_IS_AI_ENABLED)) + { + m_is_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE, false); + } + else if (propertiesObject.HasKey(JSON_KEY_IS_OPEN_AI_ENABLED)) + { + m_is_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_OPEN_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE, false); + } + else + { + m_is_ai_enabled = false; + } + + if (propertiesObject.HasKey(JSON_KEY_SHOW_CUSTOM_PREVIEW)) + { + m_preview_custom_format_output = propertiesObject.GetNamedObject(JSON_KEY_SHOW_CUSTOM_PREVIEW).GetNamedBoolean(JSON_KEY_VALUE); + } + } + if (old_data_migrated) { m_paste_as_plain_hotkey = old_paste_as_plain_hotkey; @@ -405,31 +431,6 @@ private: } } } - - if (settingsObject.GetView().Size()) - { - const auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES); - - m_is_advanced_ai_enabled = has_advanced_ai_provider(propertiesObject); - - if (propertiesObject.HasKey(JSON_KEY_IS_AI_ENABLED)) - { - m_is_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE, false); - } - else if (propertiesObject.HasKey(JSON_KEY_IS_OPEN_AI_ENABLED)) - { - m_is_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_OPEN_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE, false); - } - else - { - m_is_ai_enabled = false; - } - - if (propertiesObject.HasKey(JSON_KEY_SHOW_CUSTOM_PREVIEW)) - { - m_preview_custom_format_output = propertiesObject.GetNamedObject(JSON_KEY_SHOW_CUSTOM_PREVIEW).GetNamedBoolean(JSON_KEY_VALUE); - } - } } // Load the settings file. diff --git a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.vcxproj b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.vcxproj index 6de7c50b55..c71c81acec 100644 --- a/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.vcxproj +++ b/src/modules/MeasureTool/MeasureToolCore/PowerToys.MeasureToolCore.vcxproj @@ -1,14 +1,16 @@  - - - - - - - - - + + + PackageReference + + + native,Version=v0.0 + + + Windows + $(WindowsTargetPlatformVersion) + true true @@ -31,6 +33,11 @@ true true + + + + + DynamicLibrary @@ -38,7 +45,6 @@ true - @@ -118,9 +124,6 @@ true - - - {caba8dfb-823b-4bf2-93ac-3f31984150d9} @@ -142,42 +145,5 @@ - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/modules/MeasureTool/MeasureToolCore/packages.config b/src/modules/MeasureTool/MeasureToolCore/packages.config deleted file mode 100644 index 6416ca5b16..0000000000 --- a/src/modules/MeasureTool/MeasureToolCore/packages.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj b/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj index 434ff088b2..3e92bd42f3 100644 --- a/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj +++ b/src/modules/MeasureTool/MeasureToolUI/MeasureToolUI.csproj @@ -73,6 +73,13 @@ - + + false + true + + + + PreserveNewest + diff --git a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj index d127de245e..bfed4af15d 100644 --- a/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj +++ b/src/modules/MouseUtils/FindMyMouse/FindMyMouse.vcxproj @@ -1,13 +1,16 @@ - - - - - - - - + + + PackageReference + + + native,Version=v0.0 + + + Windows + $(WindowsTargetPlatformVersion) + 15.0 {e94fd11c-0591-456f-899f-efc0ca548336} @@ -20,9 +23,12 @@ false true false - - packages.config + + + + + DynamicLibrary @@ -127,18 +133,18 @@ - - - - - - - - - NotUsing - - + + + + + + + + NotUsing + + + <_ToDelete Include="$(OutDir)Microsoft.Web.WebView2.Core.dll" /> @@ -148,38 +154,4 @@ - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/modules/MouseUtils/FindMyMouse/packages.config b/src/modules/MouseUtils/FindMyMouse/packages.config deleted file mode 100644 index cff3aa8705..0000000000 --- a/src/modules/MouseUtils/FindMyMouse/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/modules/cmdpal/CoreCommonProps.props b/src/modules/cmdpal/CoreCommonProps.props index aa091d435e..438d044e2a 100644 --- a/src/modules/cmdpal/CoreCommonProps.props +++ b/src/modules/cmdpal/CoreCommonProps.props @@ -6,12 +6,12 @@ preview - $(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal\ + ..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\CmdPal\ false false $(RootNamespace).pri - + SA1313; @@ -42,5 +42,5 @@ Resources.Designer.cs - + diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.Branding.props b/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.Branding.props index d99688c081..298bcbd787 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.Branding.props +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.Branding.props @@ -24,7 +24,7 @@ - + true Assets\%(RecursiveDir)%(FileName)%(Extension) @@ -35,14 +35,10 @@ - - - - + + + + diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.pre.props b/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.pre.props index 21c2e7d8d1..d65b4a2cc2 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.pre.props +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/CmdPal.pre.props @@ -7,7 +7,7 @@ - $(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\CmdPal $(OutputPath)\AppPackages\ diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj b/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj index 7a413d316c..54961a5828 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Microsoft.CmdPal.UI.csproj @@ -15,7 +15,7 @@ enable enable true - preview + preview $(CmdPalVersion) @@ -23,13 +23,14 @@ false false + true - + - + --> true @@ -45,7 +46,7 @@ - + Microsoft.Terminal.UI;CmdPalKeyboardService $(OutDir) @@ -101,7 +102,7 @@ - + all runtime; build; native; contentfiles; analyzers @@ -147,12 +148,16 @@ - - True - True - True + + False + True - + + + + + PreserveNewest + True True diff --git a/src/modules/cmdpal/Microsoft.Terminal.UI/FontIconGlyphClassifier.cpp b/src/modules/cmdpal/Microsoft.Terminal.UI/FontIconGlyphClassifier.cpp index bc3496a542..e6cb46457b 100644 --- a/src/modules/cmdpal/Microsoft.Terminal.UI/FontIconGlyphClassifier.cpp +++ b/src/modules/cmdpal/Microsoft.Terminal.UI/FontIconGlyphClassifier.cpp @@ -12,9 +12,9 @@ namespace winrt::Microsoft::Terminal::UI::implementation // Check if the code point is in the Private Use Area range used by Fluent UI icons. [[nodiscard]] constexpr bool _isFluentIconPua(const UChar32 cp) noexcept { - static constexpr UChar32 _fluentIconsPrivateUseAreaStart = 0xE700; - static constexpr UChar32 _fluentIconsPrivateUseAreaEnd = 0xF8FF; - return cp >= _fluentIconsPrivateUseAreaStart && cp <= _fluentIconsPrivateUseAreaEnd; + constexpr UChar32 fluentIconsPrivateUseAreaStart = 0xE700; + constexpr UChar32 fluentIconsPrivateUseAreaEnd = 0xF8FF; + return cp >= fluentIconsPrivateUseAreaStart && cp <= fluentIconsPrivateUseAreaEnd; } // Determine if the given text (as a sequence of UChar code units) is emoji diff --git a/src/modules/cmdpal/Microsoft.Terminal.UI/Microsoft.Terminal.UI.vcxproj b/src/modules/cmdpal/Microsoft.Terminal.UI/Microsoft.Terminal.UI.vcxproj index 6e474cf5f3..676d7297ba 100644 --- a/src/modules/cmdpal/Microsoft.Terminal.UI/Microsoft.Terminal.UI.vcxproj +++ b/src/modules/cmdpal/Microsoft.Terminal.UI/Microsoft.Terminal.UI.vcxproj @@ -1,17 +1,16 @@  - - - ..\..\..\..\ - $(PathToRoot)packages\Microsoft.WindowsAppSDK.1.8.250907003 + + + PackageReference + + native,Version=v0.0 + + Windows + $(WindowsTargetPlatformVersion) + + - - - - - - - true true @@ -28,6 +27,11 @@ 10.0.26100.0 10.0.19041.0 + + + + + @@ -47,10 +51,6 @@ x64 - - $(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal - obj\$(Platform)\$(Configuration)\ - DynamicLibrary v143 @@ -200,43 +200,11 @@ - + + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\CmdPal + obj\$(Platform)\$(Configuration)\ + - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/modules/cmdpal/Microsoft.Terminal.UI/packages.config b/src/modules/cmdpal/Microsoft.Terminal.UI/packages.config deleted file mode 100644 index 2fb34c8fed..0000000000 --- a/src/modules/cmdpal/Microsoft.Terminal.UI/packages.config +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/modules/powerrename/PowerRenameUILib/PowerRenameUI.vcxproj b/src/modules/powerrename/PowerRenameUILib/PowerRenameUI.vcxproj index eb21a94049..de71eb2188 100644 --- a/src/modules/powerrename/PowerRenameUILib/PowerRenameUI.vcxproj +++ b/src/modules/powerrename/PowerRenameUILib/PowerRenameUI.vcxproj @@ -1,18 +1,16 @@  - - - - - - - - - - - - - + + + PackageReference + + + native,Version=v0.0 + + + Windows + $(WindowsTargetPlatformVersion) + true true @@ -37,9 +35,17 @@ true PowerToys.PowerRename.pri + win10-x64;win10-arm64 + false + + + + + + + - Application v143 @@ -212,54 +218,10 @@ - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - - - - - - - - - - - + - \ No newline at end of file + diff --git a/src/runner/packages.config b/src/runner/packages.config deleted file mode 100644 index 74d5ef5747..0000000000 --- a/src/runner/packages.config +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/runner/runner.vcxproj b/src/runner/runner.vcxproj index be39555d17..1bfd036290 100644 --- a/src/runner/runner.vcxproj +++ b/src/runner/runner.vcxproj @@ -1,27 +1,34 @@  - + 81010002 + + + PackageReference + + native,Version=v0.0 + + Windows + $(WindowsTargetPlatformVersion) + 15.0 {9412D5C6-2CF2-4FC2-A601-B55508EA9B27} powertoys runner + + + + + + - - - - - - - - Application @@ -31,10 +38,6 @@ true - - - - @@ -132,9 +135,6 @@ {17da04df-e393-4397-9cf0-84dabe11032e} - - - @@ -143,39 +143,15 @@ - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - - - - + + + + + + + + NotUsing + + \ No newline at end of file diff --git a/src/runner/runner.vcxproj.filters b/src/runner/runner.vcxproj.filters index 1f18128cbc..ac5fe3ec36 100644 --- a/src/runner/runner.vcxproj.filters +++ b/src/runner/runner.vcxproj.filters @@ -124,7 +124,6 @@ - diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs index faf31b0d4d..130230e2d9 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/AdvancedPastePage.xaml.cs @@ -314,10 +314,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views string selectedType = draft.ServiceType ?? string.Empty; AIServiceType serviceKind = draft.ServiceTypeKind; - bool requiresEndpoint = serviceKind is AIServiceType.AzureOpenAI - or AIServiceType.AzureAIInference - or AIServiceType.Mistral - or AIServiceType.Ollama; + bool requiresEndpoint = RequiresEndpointForService(serviceKind); bool requiresDeployment = serviceKind == AIServiceType.AzureOpenAI; bool requiresApiVersion = serviceKind == AIServiceType.AzureOpenAI; bool requiresModelPath = serviceKind == AIServiceType.Onnx; @@ -788,12 +785,17 @@ namespace Microsoft.PowerToys.Settings.UI.Views string serviceType = draft.ServiceType ?? "OpenAI"; string apiKey = PasteAIApiKeyPasswordBox.Password; string trimmedApiKey = apiKey?.Trim() ?? string.Empty; + var serviceKind = draft.ServiceTypeKind; + bool requiresEndpoint = RequiresEndpointForService(serviceKind); string endpoint = (draft.EndpointUrl ?? string.Empty).Trim(); - if (endpoint == string.Empty) + + // Never persist placeholder text or stale values for services that don't use an endpoint. + if (!requiresEndpoint) { - endpoint = GetEndpointPlaceholder(draft.ServiceTypeKind); + endpoint = string.Empty; } + // For endpoint-based services, keep empty if the user didn't provide a value. if (RequiresApiKeyForService(serviceType) && string.IsNullOrWhiteSpace(trimmedApiKey)) { args.Cancel = true; @@ -833,6 +835,14 @@ namespace Microsoft.PowerToys.Settings.UI.Views }; } + private static bool RequiresEndpointForService(AIServiceType serviceKind) + { + return serviceKind is AIServiceType.AzureOpenAI + or AIServiceType.AzureAIInference + or AIServiceType.Mistral + or AIServiceType.Ollama; + } + private static string GetEndpointPlaceholder(AIServiceType serviceKind) { return serviceKind switch @@ -841,7 +851,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views AIServiceType.AzureAIInference => "https://{resource-name}.cognitiveservices.azure.com/", AIServiceType.Mistral => "https://api.mistral.ai/v1/", AIServiceType.Ollama => "http://localhost:11434/", - _ => "https://your-resource.openai.azure.com/", + _ => string.Empty, }; }