diff --git a/PowerToys.sln b/PowerToys.sln index d46758945b..ab0a621481 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -499,8 +499,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseJumpUI", "src\modules\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AdvancedPaste", "AdvancedPaste", "{9873BA05-4C41-4819-9283-CF45D795431B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AdvancedPasteModuleInterface", "src\modules\AdvancedPaste\AdvancedPasteModuleInterface\AdvancedPasteModuleInterface.vcxproj", "{FC373B24-3293-453C-AAF5-CF2909DCEE6A}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AllExperiments", "src\common\AllExperiments\AllExperiments.csproj", "{9CE59ED5-7087-4353-88EB-788038A73CEC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RegistryPreviewUILib", "src\modules\registrypreview\RegistryPreviewUILib\RegistryPreviewUILib.csproj", "{FD86C06A-FB54-4D5E-9831-1CDADF60D45F}" @@ -2018,14 +2016,6 @@ Global {D962A009-834F-4EEC-AABB-430DF8F98E39}.Release|ARM64.Build.0 = Release|ARM64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Release|x64.ActiveCfg = Release|x64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Release|x64.Build.0 = Release|x64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Debug|ARM64.Build.0 = Debug|ARM64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Debug|x64.ActiveCfg = Debug|x64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Debug|x64.Build.0 = Debug|x64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Release|ARM64.ActiveCfg = Release|ARM64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Release|ARM64.Build.0 = Release|ARM64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Release|x64.ActiveCfg = Release|x64 - {FC373B24-3293-453C-AAF5-CF2909DCEE6A}.Release|x64.Build.0 = Release|x64 {9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|ARM64.ActiveCfg = Debug|ARM64 {9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|ARM64.Build.0 = Debug|ARM64 {9CE59ED5-7087-4353-88EB-788038A73CEC}.Debug|x64.ActiveCfg = Debug|x64 @@ -3191,7 +3181,6 @@ Global {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {2C318EC3-BA86-4372-B1BC-DB0F33C208B2} {D962A009-834F-4EEC-AABB-430DF8F98E39} = {322566EF-20DC-43A6-B9F8-616AF942579A} {9873BA05-4C41-4819-9283-CF45D795431B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} - {FC373B24-3293-453C-AAF5-CF2909DCEE6A} = {9873BA05-4C41-4819-9283-CF45D795431B} {9CE59ED5-7087-4353-88EB-788038A73CEC} = {1AFB6476-670D-4E80-A464-657E01DFF482} {FD86C06A-FB54-4D5E-9831-1CDADF60D45F} = {929C1324-22E8-4412-A9A8-80E85F3985A5} {697C6AF9-0A48-49A9-866C-67DA12384015} = {929C1324-22E8-4412-A9A8-80E85F3985A5} diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPaste.base.rc b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPaste.base.rc deleted file mode 100644 index b30e3923c9..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPaste.base.rc +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "resource.h" -#include "../../../../common/version/version.h" - -#define APSTUDIO_READONLY_SYMBOLS -#include "winres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -1 VERSIONINFO -FILEVERSION FILE_VERSION -PRODUCTVERSION PRODUCT_VERSION -FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG -FILEFLAGS VS_FF_DEBUG -#else -FILEFLAGS 0x0L -#endif -FILEOS VOS_NT_WINDOWS32 -FILETYPE VFT_DLL -FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset - BEGIN - VALUE "CompanyName", COMPANY_NAME - VALUE "FileDescription", FILE_DESCRIPTION - VALUE "FileVersion", FILE_VERSION_STRING - VALUE "InternalName", INTERNAL_NAME - VALUE "LegalCopyright", COPYRIGHT_NOTE - VALUE "OriginalFilename", ORIGINAL_FILENAME - VALUE "ProductName", PRODUCT_NAME - VALUE "ProductVersion", PRODUCT_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset - END -END diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteConstants.h b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteConstants.h deleted file mode 100644 index f978f6cee1..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteConstants.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -namespace AdvancedPasteConstants -{ - // Name of the powertoy module. - inline const std::wstring ModuleKey = L"AdvancedPaste"; -} \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj deleted file mode 100644 index 2cf2920673..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - 15.0 - Win32Proj - {FC373B24-3293-453C-AAF5-CF2909DCEE6A} - AdvancedPaste - AdvancedPasteModuleInterface - PowerToys.AdvancedPasteModuleInterface - - - - DynamicLibrary - v143 - - - - - - - - - - - - ..\..\..\..\$(Platform)\$(Configuration)\ - - - - EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - ..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) - - - $(OutDir)$(TargetName)$(TargetExt) - - - - - - - - - - - - - - - - Create - - - - - - {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} - - - {6955446d-23f7-4023-9bb3-8657f904af99} - - - - - - - - - Designer - - - - - - - - - - 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/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj.filters b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj.filters deleted file mode 100644 index aa107e28db..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteModuleInterface.vcxproj.filters +++ /dev/null @@ -1,68 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {875a08c6-f610-4667-bd0f-80171ed96072} - - - - - Header Files - - - Generated Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Resource Files - - - - Resource Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteProcessManager.cpp b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteProcessManager.cpp deleted file mode 100644 index b202f93f4e..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteProcessManager.cpp +++ /dev/null @@ -1,267 +0,0 @@ -#include "pch.h" -#include "AdvancedPasteProcessManager.h" - -#include -#include -#include -#include - -namespace -{ - std::optional get_pipe_name(const std::wstring& prefix) - { - UUID temp_uuid; - wchar_t* uuid_chars = nullptr; - if (UuidCreate(&temp_uuid) == RPC_S_UUID_NO_ADDRESS) - { - const auto val = get_last_error_message(GetLastError()); - Logger::error(L"UuidCreate cannot create guid. {}", val.has_value() ? val.value() : L""); - return std::nullopt; - } - else if (UuidToString(&temp_uuid, reinterpret_cast(&uuid_chars)) != RPC_S_OK) - { - const auto val = get_last_error_message(GetLastError()); - Logger::error(L"UuidToString cannot convert to string. {}", val.has_value() ? val.value() : L""); - return std::nullopt; - } - - const auto pipe_name = std::format(L"{}{}", prefix, std::wstring(uuid_chars)); - RpcStringFree(reinterpret_cast(&uuid_chars)); - - return pipe_name; - } -} - -void AdvancedPasteProcessManager::start() -{ - m_enabled = true; - submit_task([this]() { refresh(); }); -} - -void AdvancedPasteProcessManager::stop() -{ - m_enabled = false; - submit_task([this]() { refresh(); }); -} - -void AdvancedPasteProcessManager::send_message(const std::wstring& message_type, const std::wstring& message_arg) -{ - submit_task([this, message_type, message_arg] { - send_named_pipe_message(message_type, message_arg); - }); -} - -void AdvancedPasteProcessManager::bring_to_front() -{ - submit_task([this] { - if (!is_process_running()) - { - return; - } - - const auto enum_windows = [](HWND hwnd, LPARAM param) -> BOOL { - const auto process_handle = reinterpret_cast(param); - DWORD window_process_id = 0; - - GetWindowThreadProcessId(hwnd, &window_process_id); - if (GetProcessId(process_handle) == window_process_id) - { - SetForegroundWindow(hwnd); - return FALSE; - } - return TRUE; - }; - - EnumWindows(enum_windows, reinterpret_cast(m_hProcess)); - }); -} - -void AdvancedPasteProcessManager::submit_task(std::function task) -{ - m_thread_executor.submit(OnThreadExecutor::task_t{ task }); -} - -bool AdvancedPasteProcessManager::is_process_running() const -{ - return m_hProcess != 0 && WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT; -} - -void AdvancedPasteProcessManager::terminate_process() -{ - if (m_hProcess != 0) - { - TerminateProcess(m_hProcess, 1); - CloseHandle(m_hProcess); - m_hProcess = 0; - } -} - -HRESULT AdvancedPasteProcessManager::start_process(const std::wstring& pipe_name) -{ - const unsigned long powertoys_pid = GetCurrentProcessId(); - - const auto executable_args = std::format(L"{} {}", std::to_wstring(powertoys_pid), pipe_name); - - SHELLEXECUTEINFOW sei{ sizeof(sei) }; - sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI }; - sei.lpFile = L"WinUI3Apps\\PowerToys.AdvancedPaste.exe"; - sei.nShow = SW_SHOWNORMAL; - sei.lpParameters = executable_args.data(); - if (ShellExecuteExW(&sei)) - { - Logger::trace("Successfully started Advanced Paste process"); - terminate_process(); - m_hProcess = sei.hProcess; - return S_OK; - } - else - { - Logger::error(L"Advanced Paste process failed to start. {}", get_last_error_or_default(GetLastError())); - return E_FAIL; - } -} - -HRESULT AdvancedPasteProcessManager::start_named_pipe_server(const std::wstring& pipe_name) -{ - m_write_pipe = nullptr; - - const constexpr DWORD BUFSIZE = 4096 * 4; - - const auto full_pipe_name = std::format(L"\\\\.\\pipe\\{}", pipe_name); - - const auto hPipe = CreateNamedPipe( - full_pipe_name.c_str(), // pipe name - PIPE_ACCESS_OUTBOUND | // write access - FILE_FLAG_OVERLAPPED, // overlapped mode - PIPE_TYPE_MESSAGE | // message type pipe - PIPE_READMODE_MESSAGE | // message-read mode - PIPE_WAIT, // blocking mode - 1, // max. instances - BUFSIZE, // output buffer size - 0, // input buffer size - 0, // client time-out - NULL); // default security attribute - - if (hPipe == NULL || hPipe == INVALID_HANDLE_VALUE) - { - Logger::error(L"Error creating handle for named pipe"); - return E_FAIL; - } - - // Create overlapped event to wait for client to connect to pipe. - OVERLAPPED overlapped = { 0 }; - overlapped.hEvent = CreateEvent(nullptr, true, false, nullptr); - if (!overlapped.hEvent) - { - Logger::error(L"Error creating overlapped event for named pipe"); - CloseHandle(hPipe); - return E_FAIL; - } - - const auto clean_up_and_fail = [&]() { - CloseHandle(overlapped.hEvent); - CloseHandle(hPipe); - return E_FAIL; - }; - - if (!ConnectNamedPipe(hPipe, &overlapped)) - { - const auto lastError = GetLastError(); - - if (lastError != ERROR_IO_PENDING && lastError != ERROR_PIPE_CONNECTED) - { - Logger::error(L"Error connecting to named pipe"); - return clean_up_and_fail(); - } - } - - // Wait for client. - const constexpr DWORD client_timeout_millis = 5000; - switch (WaitForSingleObject(overlapped.hEvent, client_timeout_millis)) - { - case WAIT_OBJECT_0: - { - DWORD bytes_transferred = 0; - if (GetOverlappedResult(hPipe, &overlapped, &bytes_transferred, FALSE)) - { - CloseHandle(overlapped.hEvent); - m_write_pipe = std::make_unique(hPipe); - - Logger::trace(L"Advanced Paste successfully connected to named pipe"); - - return S_OK; - } - else - { - Logger::error(L"Error waiting for Advanced Paste to connect to named pipe"); - return clean_up_and_fail(); - } - } - - case WAIT_TIMEOUT: - case WAIT_FAILED: - default: - Logger::error(L"Error waiting for Advanced Paste to connect to named pipe"); - return clean_up_and_fail(); - } -} - -void AdvancedPasteProcessManager::refresh() -{ - if (m_enabled == is_process_running()) - { - return; - } - - if (m_enabled) - { - Logger::trace(L"Starting Advanced Paste process"); - - const auto pipe_name = get_pipe_name(L"powertoys_advanced_paste_"); - - if (!pipe_name) - { - return; - } - - if (start_process(pipe_name.value()) != S_OK) - { - return; - } - - if (start_named_pipe_server(pipe_name.value()) != S_OK) - { - Logger::error(L"Named pipe initialization failed; terminating Advanced Paste process"); - terminate_process(); - } - } - else - { - Logger::trace(L"Exiting Advanced Paste process"); - - send_named_pipe_message(CommonSharedConstants::ADVANCED_PASTE_TERMINATE_APP_MESSAGE); - WaitForSingleObject(m_hProcess, 5000); - - if (is_process_running()) - { - Logger::error(L"Advanced Paste process failed to gracefully exit; terminating"); - } - else - { - Logger::trace(L"Advanced Paste process successfully exited"); - } - - terminate_process(); - } -} - -void AdvancedPasteProcessManager::send_named_pipe_message(const std::wstring& message_type, const std::wstring& message_arg) -{ - if (m_write_pipe) - { - const auto message = message_arg.empty() ? std::format(L"{}\r\n", message_type) : std::format(L"{} {}\r\n", message_type, message_arg); - - const CString file_name(message.c_str()); - m_write_pipe->Write(file_name, file_name.GetLength() * sizeof(TCHAR)); - } -} \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteProcessManager.h b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteProcessManager.h deleted file mode 100644 index acef16bcee..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/AdvancedPasteProcessManager.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "pch.h" -#include -#include -#include -#include -#include -#include -#include - -class AdvancedPasteProcessManager -{ -public: - AdvancedPasteProcessManager() = default; - AdvancedPasteProcessManager(const AdvancedPasteProcessManager&) = delete; - AdvancedPasteProcessManager& operator=(const AdvancedPasteProcessManager&) = delete; - - void start(); - void stop(); - void send_message(const std::wstring& message_type, const std::wstring& message_arg = L""); - void bring_to_front(); - -private: - void submit_task(std::function task); - bool is_process_running() const; - void terminate_process(); - HRESULT start_process(const std::wstring& pipe_name); - HRESULT start_named_pipe_server(const std::wstring& pipe_name); - void refresh(); - void send_named_pipe_message(const std::wstring& message_type, const std::wstring& message_arg = L""); - - OnThreadExecutor m_thread_executor; // all internal operations are done on background thread with task queue - std::atomic m_enabled = false; // written on main thread, read on background thread - HANDLE m_hProcess = 0; - std::unique_ptr m_write_pipe; -}; \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/Resources.resx b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/Resources.resx deleted file mode 100644 index f32af52c10..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/Resources.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Advanced Paste - - - An AI powered tool to put your clipboard content into any format you need, focused towards developer workflows. - - \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp deleted file mode 100644 index c7d22d474f..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/dllmain.cpp +++ /dev/null @@ -1,909 +0,0 @@ -// dllmain.cpp : Defines the entry point for the DLL application. -#include "pch.h" - -#include "AdvancedPasteConstants.h" -#include "AdvancedPasteProcessManager.h" -#include -#include "trace.h" -#include "Generated Files/resource.h" -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*lpReserved*/) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - Trace::RegisterProvider(); - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - Trace::UnregisterProvider(); - break; - } - return TRUE; -} - -namespace -{ - const wchar_t JSON_KEY_PROPERTIES[] = L"properties"; - const wchar_t JSON_KEY_CUSTOM_ACTIONS[] = L"custom-actions"; - const wchar_t JSON_KEY_ADDITIONAL_ACTIONS[] = L"additional-actions"; - const wchar_t JSON_KEY_SHORTCUT[] = L"shortcut"; - const wchar_t JSON_KEY_IS_SHOWN[] = L"isShown"; - const wchar_t JSON_KEY_ID[] = L"id"; - const wchar_t JSON_KEY_WIN[] = L"win"; - const wchar_t JSON_KEY_ALT[] = L"alt"; - const wchar_t JSON_KEY_CTRL[] = L"ctrl"; - const wchar_t JSON_KEY_SHIFT[] = L"shift"; - const wchar_t JSON_KEY_CODE[] = L"code"; - const wchar_t JSON_KEY_PASTE_AS_PLAIN_HOTKEY[] = L"paste-as-plain-hotkey"; - const wchar_t JSON_KEY_ADVANCED_PASTE_UI_HOTKEY[] = L"advanced-paste-ui-hotkey"; - const wchar_t JSON_KEY_PASTE_AS_MARKDOWN_HOTKEY[] = L"paste-as-markdown-hotkey"; - const wchar_t JSON_KEY_PASTE_AS_JSON_HOTKEY[] = L"paste-as-json-hotkey"; - const wchar_t JSON_KEY_IS_AI_ENABLED[] = L"IsAIEnabled"; - const wchar_t JSON_KEY_IS_OPEN_AI_ENABLED[] = L"IsOpenAIEnabled"; - const wchar_t JSON_KEY_SHOW_CUSTOM_PREVIEW[] = L"ShowCustomPreview"; - const wchar_t JSON_KEY_PASTE_AI_CONFIGURATION[] = L"paste-ai-configuration"; - const wchar_t JSON_KEY_PROVIDERS[] = L"providers"; - const wchar_t JSON_KEY_SERVICE_TYPE[] = L"service-type"; - const wchar_t JSON_KEY_ENABLE_ADVANCED_AI[] = L"enable-advanced-ai"; - const wchar_t JSON_KEY_VALUE[] = L"value"; -} - -class AdvancedPaste : public PowertoyModuleIface -{ -private: - - AdvancedPasteProcessManager m_process_manager; - bool m_enabled = false; - - std::wstring app_name; - - //contains the non localized key of the powertoy - std::wstring app_key; - - static const constexpr int NUM_DEFAULT_HOTKEYS = 4; - - Hotkey m_paste_as_plain_hotkey = { .win = true, .ctrl = true, .shift = false, .alt = true, .key = 'V' }; - Hotkey m_advanced_paste_ui_hotkey = { .win = true, .ctrl = false, .shift = true, .alt = false, .key = 'V' }; - Hotkey m_paste_as_markdown_hotkey{}; - Hotkey m_paste_as_json_hotkey{}; - - template - struct ActionData - { - Id id; - Hotkey hotkey; - }; - - using AdditionalAction = ActionData; - std::vector m_additional_actions; - - using CustomAction = ActionData; - std::vector m_custom_actions; - - bool m_is_ai_enabled = false; - bool m_is_advanced_ai_enabled = false; - bool m_preview_custom_format_output = true; - - Hotkey parse_single_hotkey(const wchar_t* keyName, const winrt::Windows::Data::Json::JsonObject& settingsObject) - { - try - { - const auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).GetNamedObject(keyName); - return parse_single_hotkey(jsonHotkeyObject); - } - catch (...) - { - Logger::error("Failed to initialize AdvancedPaste shortcut from settings. Value will keep unchanged."); - } - - return {}; - } - - static Hotkey parse_single_hotkey(const winrt::Windows::Data::Json::JsonObject& jsonHotkeyObject, bool isShown = true) - { - try - { - Hotkey hotkey; - hotkey.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN); - hotkey.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT); - hotkey.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT); - hotkey.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL); - hotkey.key = static_cast(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE)); - hotkey.isShown = isShown; - return hotkey; - } - catch (...) - { - Logger::error("Failed to initialize AdvancedPaste shortcut from settings. Value will keep unchanged."); - } - - return {}; - } - - static json::JsonObject to_json_object(const Hotkey& hotkey) - { - json::JsonObject jsonObject; - jsonObject.SetNamedValue(JSON_KEY_WIN, json::value(hotkey.win)); - jsonObject.SetNamedValue(JSON_KEY_ALT, json::value(hotkey.alt)); - jsonObject.SetNamedValue(JSON_KEY_SHIFT, json::value(hotkey.shift)); - jsonObject.SetNamedValue(JSON_KEY_CTRL, json::value(hotkey.ctrl)); - jsonObject.SetNamedValue(JSON_KEY_CODE, json::value(hotkey.key)); - - return jsonObject; - } - - bool is_ai_enabled() - { - return gpo_policy_enabled_configuration() != powertoys_gpo::gpo_rule_configured_disabled && - powertoys_gpo::getAllowedAdvancedPasteOnlineAIModelsValue() != powertoys_gpo::gpo_rule_configured_disabled && - m_is_ai_enabled; - } - - static std::wstring kebab_to_pascal_case(const std::wstring& kebab_str) - { - std::wstring result; - bool capitalize_next = true; - - for (const auto ch : kebab_str) - { - if (ch == L'-') - { - capitalize_next = true; - } - else - { - if (capitalize_next) - { - result += std::towupper(ch); - capitalize_next = false; - } - else - { - result += ch; - } - } - } - - return result; - } - - static std::wstring to_lower_case(const std::wstring& value) - { - std::wstring result = value; - std::transform(result.begin(), result.end(), result.begin(), [](wchar_t ch) { return std::towlower(ch); }); - return result; - } - - bool migrate_data_and_remove_data_file(Hotkey& old_paste_as_plain_hotkey) - { - const wchar_t OLD_JSON_KEY_ACTIVATION_SHORTCUT[] = L"ActivationShortcut"; - const wchar_t OLD_MODULE_KEY[] = L"PastePlain"; - - try - { - const std::wstring save_file_location = PTSettingsHelper::get_module_save_file_location(OLD_MODULE_KEY); - if (std::filesystem::exists(save_file_location)) - { - PowerToysSettings::PowerToyValues settings = - PowerToysSettings::PowerToyValues::load_from_settings_file(OLD_MODULE_KEY); - - auto settingsObject = settings.get_raw_json(); - if (settingsObject.GetView().Size()) - { - old_paste_as_plain_hotkey = parse_single_hotkey(OLD_JSON_KEY_ACTIVATION_SHORTCUT, settingsObject); - - std::filesystem::remove(save_file_location); - - return true; - } - } - } - catch (std::exception) - { - } - - return false; - } - - void process_additional_action(const winrt::hstring& actionName, const winrt::Windows::Data::Json::IJsonValue& actionValue, bool actionsGroupIsShown = true) - { - bool actionIsShown = true; - - if (actionValue.ValueType() != winrt::Windows::Data::Json::JsonValueType::Object) - { - return; - } - - const auto action = actionValue.GetObjectW(); - - if (!action.GetNamedBoolean(JSON_KEY_IS_SHOWN, false) || !actionsGroupIsShown) - { - actionIsShown = false; - } - - if (action.HasKey(JSON_KEY_SHORTCUT)) - { - const AdditionalAction additionalAction - { - actionName.c_str(), - parse_single_hotkey(action.GetNamedObject(JSON_KEY_SHORTCUT), actionIsShown) - }; - - m_additional_actions.push_back(additionalAction); - } - else - { - for (const auto& [subActionName, subAction] : action) - { - process_additional_action(subActionName, subAction, actionIsShown); - } - } - } - - bool has_advanced_ai_provider(const winrt::Windows::Data::Json::JsonObject& propertiesObject) - { - if (!propertiesObject.HasKey(JSON_KEY_PASTE_AI_CONFIGURATION)) - { - return false; - } - - const auto configValue = propertiesObject.GetNamedValue(JSON_KEY_PASTE_AI_CONFIGURATION); - if (configValue.ValueType() != winrt::Windows::Data::Json::JsonValueType::Object) - { - return false; - } - - const auto configObject = configValue.GetObjectW(); - if (!configObject.HasKey(JSON_KEY_PROVIDERS)) - { - return false; - } - - const auto providersValue = configObject.GetNamedValue(JSON_KEY_PROVIDERS); - if (providersValue.ValueType() != winrt::Windows::Data::Json::JsonValueType::Array) - { - return false; - } - - const auto providers = providersValue.GetArray(); - for (const auto providerValue : providers) - { - if (providerValue.ValueType() != winrt::Windows::Data::Json::JsonValueType::Object) - { - continue; - } - - const auto providerObject = providerValue.GetObjectW(); - if (!providerObject.GetNamedBoolean(JSON_KEY_ENABLE_ADVANCED_AI, false)) - { - continue; - } - - if (!providerObject.HasKey(JSON_KEY_SERVICE_TYPE)) - { - continue; - } - - const std::wstring serviceType = providerObject.GetNamedString(JSON_KEY_SERVICE_TYPE, L"").c_str(); - const auto normalizedServiceType = to_lower_case(serviceType); - if (normalizedServiceType == L"openai" || normalizedServiceType == L"azureopenai") - { - return true; - } - } - - return false; - } - - 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 (old_data_migrated) - { - m_paste_as_plain_hotkey = old_paste_as_plain_hotkey; - - // override settings file - const auto new_hotkey_value = to_json_object(old_paste_as_plain_hotkey); - - if (!settingsObject.HasKey(JSON_KEY_PROPERTIES)) - { - settingsObject.SetNamedValue(JSON_KEY_PROPERTIES, json::JsonObject{}); - } - - settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).SetNamedValue(JSON_KEY_PASTE_AS_PLAIN_HOTKEY, new_hotkey_value); - - const auto ui_hotkey = to_json_object(m_advanced_paste_ui_hotkey); - settingsObject.GetNamedObject(JSON_KEY_PROPERTIES).SetNamedValue(JSON_KEY_ADVANCED_PASTE_UI_HOTKEY, ui_hotkey); - - settings.save_to_settings_file(); - } - else - { - if (settingsObject.GetView().Size()) - { - const std::array, NUM_DEFAULT_HOTKEYS> defaultHotkeys{ - { { &m_paste_as_plain_hotkey, JSON_KEY_PASTE_AS_PLAIN_HOTKEY }, - { &m_advanced_paste_ui_hotkey, JSON_KEY_ADVANCED_PASTE_UI_HOTKEY }, - { &m_paste_as_markdown_hotkey, JSON_KEY_PASTE_AS_MARKDOWN_HOTKEY }, - { &m_paste_as_json_hotkey, JSON_KEY_PASTE_AS_JSON_HOTKEY } } - }; - - for (auto& [hotkey, keyName] : defaultHotkeys) - { - *hotkey = parse_single_hotkey(keyName, settingsObject); - } - - m_additional_actions.clear(); - m_custom_actions.clear(); - - if (settingsObject.HasKey(JSON_KEY_PROPERTIES)) - { - const auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES); - - if (propertiesObject.HasKey(JSON_KEY_ADDITIONAL_ACTIONS)) - { - const auto additionalActions = propertiesObject.GetNamedObject(JSON_KEY_ADDITIONAL_ACTIONS); - - // Define the expected order to ensure consistent hotkey ID assignment - const std::vector expectedOrder = { - L"image-to-text", - L"paste-as-file", - L"transcode" - }; - - // Process actions in the predefined order - for (auto& actionKey : expectedOrder) - { - if (additionalActions.HasKey(actionKey)) - { - const auto actionValue = additionalActions.GetNamedValue(actionKey); - process_additional_action(actionKey, actionValue); - } - } - } - - if (propertiesObject.HasKey(JSON_KEY_CUSTOM_ACTIONS)) - { - const auto customActions = propertiesObject.GetNamedObject(JSON_KEY_CUSTOM_ACTIONS).GetNamedArray(JSON_KEY_VALUE); - if (customActions.Size() > 0 && is_ai_enabled()) - { - for (const auto& customAction : customActions) - { - const auto object = customAction.GetObjectW(); - bool actionIsShown = object.GetNamedBoolean(JSON_KEY_IS_SHOWN, false); - - const CustomAction customActionData{ - static_cast(object.GetNamedNumber(JSON_KEY_ID)), - parse_single_hotkey(object.GetNamedObject(JSON_KEY_SHORTCUT), actionIsShown) - }; - - m_custom_actions.push_back(customActionData); - } - } - } - } - } - } - - 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. - void init_settings() - { - try - { - // Load and parse the settings file for this PowerToy. - PowerToysSettings::PowerToyValues settings = - PowerToysSettings::PowerToyValues::load_from_settings_file(get_key()); - - read_settings(settings); - } - catch (std::exception&) - { - Logger::warn(L"An exception occurred while loading the settings file"); - // Error while loading from the settings file. Let default values stay as they are. - } - } - - void try_inject_modifier_key_up(std::vector& inputs, short modifier) - { - // Most significant bit is set if key is down - if ((GetAsyncKeyState(static_cast(modifier)) & 0x8000) != 0) - { - INPUT input_event = {}; - input_event.type = INPUT_KEYBOARD; - input_event.ki.wVk = modifier; - input_event.ki.dwFlags = KEYEVENTF_KEYUP; - inputs.push_back(input_event); - } - } - - void try_inject_modifier_key_restore(std::vector& inputs, short modifier) - { - // Most significant bit is set if key is down - if ((GetAsyncKeyState(static_cast(modifier)) & 0x8000) != 0) - { - INPUT input_event = {}; - input_event.type = INPUT_KEYBOARD; - input_event.ki.wVk = modifier; - inputs.push_back(input_event); - } - } - - void try_to_paste_as_plain_text() - { - std::wstring clipboard_text; - - { - // Read clipboard data begin - - if (!OpenClipboard(NULL)) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't open the clipboard to get the text. {}", errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"read.OpenClipboard"); - return; - } - HANDLE h_clipboard_data = GetClipboardData(CF_UNICODETEXT); - - if (h_clipboard_data == NULL) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Failed to get clipboard data. {}", errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"read.GetClipboardData"); - CloseClipboard(); - return; - } - - wchar_t* pch_data = static_cast(GlobalLock(h_clipboard_data)); - - if (NULL == pch_data) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't lock the buffer to get the unformatted text from the clipboard. {}", errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"read.GlobalLock"); - CloseClipboard(); - return; - } - - clipboard_text = pch_data; - GlobalUnlock(h_clipboard_data); - - CloseClipboard(); - // Read clipboard data end - } - - { - // Copy text to clipboard begin - UINT no_clipboard_history_or_roaming_format = 0; - - // Get the format identifier for not adding the data to the clipboard history or roaming. - // https://learn.microsoft.com/windows/win32/dataxchg/clipboard-formats#cloud-clipboard-and-clipboard-history-formats - if (0 == (no_clipboard_history_or_roaming_format = RegisterClipboardFormat(L"ExcludeClipboardContentFromMonitorProcessing"))) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't get the clipboard data format type that would allow excluding the data from the clipboard history / roaming. {}", errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"write.RegisterClipboardFormat"); - return; - } - - if (!OpenClipboard(NULL)) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't open the clipboard to copy the unformatted text. {}", errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"write.OpenClipboard"); - return; - } - - HGLOBAL h_clipboard_data; - - if (NULL == (h_clipboard_data = GlobalAlloc(GMEM_MOVEABLE, (clipboard_text.length() + 1) * sizeof(wchar_t)))) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't allocate a buffer for the unformatted text. {}", errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"write.GlobalAlloc"); - CloseClipboard(); - return; - } - wchar_t* pch_data = static_cast(GlobalLock(h_clipboard_data)); - - if (NULL == pch_data) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't lock the buffer to send the unformatted text to the clipboard. {}", errorMessage.has_value() ? errorMessage.value() : L""); - GlobalFree(h_clipboard_data); - CloseClipboard(); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"write.GlobalLock"); - return; - } - - wcscpy_s(pch_data, clipboard_text.length() + 1, clipboard_text.c_str()); - - EmptyClipboard(); - - if (NULL == SetClipboardData(CF_UNICODETEXT, h_clipboard_data)) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"Couldn't set the clipboard data to the unformatted text. {}", errorMessage.has_value() ? errorMessage.value() : L""); - GlobalUnlock(h_clipboard_data); - GlobalFree(h_clipboard_data); - CloseClipboard(); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"write.SetClipboardData"); - return; - } - - // Don't show in history or allow data roaming. - SetClipboardData(no_clipboard_history_or_roaming_format, 0); - - CloseClipboard(); - // Copy text to clipboard end - } - { - // Clear kb state and send Ctrl+V begin - - // we can assume that the last pressed key is... - // (1) not a modifier key and - // (2) marked as handled (so it never gets a key down input event). - // So, let's check which modifiers were pressed, - // and, if they were, inject a key up event for each of them - std::vector inputs; - try_inject_modifier_key_up(inputs, VK_LCONTROL); - try_inject_modifier_key_up(inputs, VK_RCONTROL); - try_inject_modifier_key_up(inputs, VK_LWIN); - try_inject_modifier_key_up(inputs, VK_RWIN); - try_inject_modifier_key_up(inputs, VK_LSHIFT); - try_inject_modifier_key_up(inputs, VK_RSHIFT); - try_inject_modifier_key_up(inputs, VK_LMENU); - try_inject_modifier_key_up(inputs, VK_RMENU); - - // send Ctrl+V (key downs and key ups) - { - INPUT input_event = {}; - input_event.type = INPUT_KEYBOARD; - input_event.ki.wVk = VK_CONTROL; - inputs.push_back(input_event); - } - - { - INPUT input_event = {}; - input_event.type = INPUT_KEYBOARD; - input_event.ki.wVk = 0x56; // V - // Avoid triggering detection by the centralized keyboard hook. Allows using Control+V as activation. - input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG; - inputs.push_back(input_event); - } - - { - INPUT input_event = {}; - input_event.type = INPUT_KEYBOARD; - input_event.ki.wVk = 0x56; // V - input_event.ki.dwFlags = KEYEVENTF_KEYUP; - // Avoid triggering detection by the centralized keyboard hook. Allows using Control+V as activation. - input_event.ki.dwExtraInfo = CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG; - inputs.push_back(input_event); - } - - { - INPUT input_event = {}; - input_event.type = INPUT_KEYBOARD; - input_event.ki.wVk = VK_CONTROL; - input_event.ki.dwFlags = KEYEVENTF_KEYUP; - inputs.push_back(input_event); - } - - try_inject_modifier_key_restore(inputs, VK_LCONTROL); - try_inject_modifier_key_restore(inputs, VK_RCONTROL); - try_inject_modifier_key_restore(inputs, VK_LWIN); - try_inject_modifier_key_restore(inputs, VK_RWIN); - try_inject_modifier_key_restore(inputs, VK_LSHIFT); - try_inject_modifier_key_restore(inputs, VK_RSHIFT); - try_inject_modifier_key_restore(inputs, VK_LMENU); - try_inject_modifier_key_restore(inputs, VK_RMENU); - - // After restoring the modifier keys send a dummy key to prevent Start Menu from activating - INPUT dummyEvent = {}; - dummyEvent.type = INPUT_KEYBOARD; - dummyEvent.ki.wVk = 0xFF; - dummyEvent.ki.dwFlags = KEYEVENTF_KEYUP; - inputs.push_back(dummyEvent); - - auto uSent = SendInput(static_cast(inputs.size()), inputs.data(), sizeof(INPUT)); - if (uSent != inputs.size()) - { - DWORD errorCode = GetLastError(); - auto errorMessage = get_last_error_message(errorCode); - Logger::error(L"SendInput failed. Expected to send {} inputs and sent only {}. {}", inputs.size(), uSent, errorMessage.has_value() ? errorMessage.value() : L""); - Trace::AdvancedPaste_Error(errorCode, errorMessage.has_value() ? errorMessage.value() : L"", L"input.SendInput"); - return; - } - - // Clear kb state and send Ctrl+V end - } - } - -public: - AdvancedPaste() - { - app_name = GET_RESOURCE_STRING(IDS_ADVANCED_PASTE_NAME); - app_key = AdvancedPasteConstants::ModuleKey; - LoggerHelpers::init_logger(app_key, L"ModuleInterface", "AdvancedPaste"); - init_settings(); - } - - ~AdvancedPaste() - { - if (m_enabled) - { - } - m_enabled = false; - } - - // Destroy the powertoy and free memory - virtual void destroy() override - { - Disable(false); - - Logger::trace("AdvancedPaste::destroy()"); - delete this; - } - - // Return the localized display name of the powertoy - virtual const wchar_t* get_name() override - { - return app_name.c_str(); - } - - // Return the non localized key of the powertoy, this will be cached by the runner - virtual const wchar_t* get_key() override - { - return app_key.c_str(); - } - - // Return the configured status for the gpo policy for the module - virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override - { - return powertoys_gpo::getConfiguredAdvancedPasteEnabledValue(); - } - - virtual bool get_config(wchar_t* buffer, int* buffer_size) override - { - HINSTANCE hinstance = reinterpret_cast(&__ImageBase); - - // Create a Settings object. - PowerToysSettings::Settings settings(hinstance, get_name()); - settings.set_description(GET_RESOURCE_STRING(IDS_ADVANCED_PASTE_SETTINGS_DESC)); - - settings.set_overview_link(L"https://aka.ms/PowerToysOverview_AdvancedPaste"); - - return settings.serialize_to_buffer(buffer, buffer_size); - } - - virtual void call_custom_action(const wchar_t* /*action*/) override - { - } - - virtual void set_config(const wchar_t* config) override - { - try - { - // Parse the input JSON string. - PowerToysSettings::PowerToyValues values = - PowerToysSettings::PowerToyValues::from_json_string(config, get_key()); - - read_settings(values); - - std::unordered_map additionalActionMap; - for (const auto& action : m_additional_actions) - { - additionalActionMap[kebab_to_pascal_case(action.id)] = action.hotkey; - } - - // order of args matter - Trace::AdvancedPaste_SettingsTelemetry(m_paste_as_plain_hotkey, - m_advanced_paste_ui_hotkey, - m_paste_as_markdown_hotkey, - m_paste_as_json_hotkey, - m_is_advanced_ai_enabled, - m_preview_custom_format_output, - additionalActionMap); - - // If you don't need to do any custom processing of the settings, proceed - // to persists the values calling: - values.save_to_settings_file(); - // Otherwise call a custom function to process the settings before saving them to disk: - // save_settings(); - } - catch (std::exception&) - { - // Improper JSON. - } - } - - virtual void enable() - { - Logger::trace("AdvancedPaste::enable()"); - Trace::AdvancedPaste_Enable(true); - m_enabled = true; - m_process_manager.start(); - }; - - void Disable(bool traceEvent) - { - if (m_enabled) - { - m_process_manager.stop(); - - if (traceEvent) - { - Trace::AdvancedPaste_Enable(false); - } - } - - m_enabled = false; - } - - virtual void disable() - { - Logger::trace("AdvancedPaste::disable()"); - Disable(true); - } - - virtual bool on_hotkey(size_t hotkeyId) override - { - Logger::trace(L"AdvancedPaste hotkey pressed"); - if (m_enabled) - { - m_process_manager.start(); - - // hotkeyId in same order as set by get_hotkeys - if (hotkeyId == 0) - { // m_paste_as_plain_hotkey - Logger::trace(L"Paste as plain text hotkey pressed"); - - std::thread([=]() { - // hotkey work should be kept to a minimum, or Windows might deregister our low level keyboard hook. - // Move work to another thread. - try_to_paste_as_plain_text(); - }).detach(); - - Trace::AdvancedPaste_Invoked(L"PastePlainTextDirect"); - return true; - } - - if (hotkeyId == 1) - { // m_advanced_paste_ui_hotkey - Logger::trace(L"Setting start up event"); - - m_process_manager.bring_to_front(); - m_process_manager.send_message(CommonSharedConstants::ADVANCED_PASTE_SHOW_UI_MESSAGE); - Trace::AdvancedPaste_Invoked(L"AdvancedPasteUI"); - return true; - } - if (hotkeyId == 2) - { // m_paste_as_markdown_hotkey - Logger::trace(L"Starting paste as markdown directly"); - m_process_manager.send_message(CommonSharedConstants::ADVANCED_PASTE_MARKDOWN_MESSAGE); - Trace::AdvancedPaste_Invoked(L"MarkdownDirect"); - return true; - } - if (hotkeyId == 3) - { // m_paste_as_json_hotkey - Logger::trace(L"Starting paste as json directly"); - m_process_manager.send_message(CommonSharedConstants::ADVANCED_PASTE_JSON_MESSAGE); - Trace::AdvancedPaste_Invoked(L"JsonDirect"); - return true; - } - - - const auto additional_action_index = hotkeyId - NUM_DEFAULT_HOTKEYS; - if (additional_action_index < m_additional_actions.size()) - { - const auto& id = m_additional_actions.at(additional_action_index).id; - - Logger::trace(L"Starting additional action id={}", id); - - Trace::AdvancedPaste_Invoked(std::format(L"{}Direct", kebab_to_pascal_case(id))); - - m_process_manager.send_message(CommonSharedConstants::ADVANCED_PASTE_ADDITIONAL_ACTION_MESSAGE, id); - return true; - } - - const auto custom_action_index = additional_action_index - m_additional_actions.size(); - if (custom_action_index < m_custom_actions.size()) - { - const auto id = m_custom_actions.at(custom_action_index).id; - - Logger::trace(L"Starting custom action id={}", id); - - m_process_manager.send_message(CommonSharedConstants::ADVANCED_PASTE_CUSTOM_ACTION_MESSAGE, std::to_wstring(id)); - Trace::AdvancedPaste_Invoked(L"CustomActionDirect"); - return true; - } - } - - return false; - } - - virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override - { - const size_t num_hotkeys = NUM_DEFAULT_HOTKEYS + m_additional_actions.size() + m_custom_actions.size(); - - if (hotkeys && buffer_size >= num_hotkeys) - { - const std::array default_hotkeys = { m_paste_as_plain_hotkey, - m_advanced_paste_ui_hotkey, - m_paste_as_markdown_hotkey, - m_paste_as_json_hotkey }; - std::copy(default_hotkeys.begin(), default_hotkeys.end(), hotkeys); - - const auto get_action_hotkey = [](const auto& action) { return action.hotkey; }; - std::transform(m_additional_actions.begin(), m_additional_actions.end(), hotkeys + NUM_DEFAULT_HOTKEYS, get_action_hotkey); - std::transform(m_custom_actions.begin(), m_custom_actions.end(), hotkeys + NUM_DEFAULT_HOTKEYS + m_additional_actions.size(), get_action_hotkey); - } - - return num_hotkeys; - } - - virtual bool is_enabled() override - { - return m_enabled; - } -}; - -extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create() -{ - return new AdvancedPaste(); -} diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/packages.config b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/packages.config deleted file mode 100644 index 09bfc449e2..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/pch.cpp b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/pch.cpp deleted file mode 100644 index ce9b73991b..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/pch.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "pch.h" - diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/pch.h b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/pch.h deleted file mode 100644 index e730ab2036..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/pch.h +++ /dev/null @@ -1,7 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include \ No newline at end of file diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/resource.base.h b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/resource.base.h deleted file mode 100644 index c9c0bc3fd0..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/resource.base.h +++ /dev/null @@ -1,13 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by PowerOCR.rc - -////////////////////////////// -// Non-localizable - -#define FILE_DESCRIPTION "PowerToys AdvancedPaste" -#define INTERNAL_NAME "PowerToys.AdvancedPasteModuleInterface" -#define ORIGINAL_FILENAME "PowerToys.AdvancedPasteModuleInterface.dll" - -// Non-localizable -////////////////////////////// diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/trace.cpp b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/trace.cpp deleted file mode 100644 index c6b1bfa0a9..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/trace.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "pch.h" -#include "trace.h" - -TRACELOGGING_DEFINE_PROVIDER( - g_hProvider, - "Microsoft.PowerToys", - // {38e8889b-9731-53f5-e901-e8a7c1753074} - (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), - TraceLoggingOptionProjectTelemetry()); - -// Log if the user has AdvancedPaste enabled or disabled -void Trace::AdvancedPaste_Enable(const bool enabled) noexcept -{ - TraceLoggingWriteWrapper( - g_hProvider, - "AdvancedPaste_EnableAdvancedPaste", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), - TraceLoggingBoolean(enabled, "Enabled")); -} - -// Log if the user has invoked AdvancedPaste -void Trace::AdvancedPaste_Invoked(std::wstring mode) noexcept -{ - TraceLoggingWriteWrapper( - g_hProvider, - "AdvancedPaste_InvokeAdvancedPaste", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), - TraceLoggingValue(mode.c_str(), "Mode")); -} - -// Log if an error occurs in AdvancedPaste -void Trace::AdvancedPaste_Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept -{ - TraceLoggingWriteWrapper( - g_hProvider, - "AdvancedPaste_Error", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), - TraceLoggingValue(methodName.c_str(), "MethodName"), - TraceLoggingValue(errorCode, "ErrorCode"), - TraceLoggingValue(errorMessage.c_str(), "ErrorMessage")); -} - -// Event to send settings telemetry. -void Trace::AdvancedPaste_SettingsTelemetry(const PowertoyModuleIface::Hotkey& pastePlainHotkey, - const PowertoyModuleIface::Hotkey& advancedPasteUIHotkey, - const PowertoyModuleIface::Hotkey& pasteMarkdownHotkey, - const PowertoyModuleIface::Hotkey& pasteJsonHotkey, - const bool is_advanced_ai_enabled, - const bool preview_custom_format_output, - const std::unordered_map& additionalActionsHotkeys) noexcept -{ - const auto getHotKeyStr = [](const PowertoyModuleIface::Hotkey& hotKey) - { - return std::wstring(hotKey.win ? L"Win + " : L"") + - std::wstring(hotKey.ctrl ? L"Ctrl + " : L"") + - std::wstring(hotKey.shift ? L"Shift + " : L"") + - std::wstring(hotKey.alt ? L"Alt + " : L"") + - std::wstring(L"VK ") + std::to_wstring(hotKey.key); - }; - - std::vector hotkeyStrs; - const auto getHotkeyCStr = [&](const PowertoyModuleIface::Hotkey& hotkey) - { - hotkeyStrs.push_back(getHotKeyStr(hotkey)); // Probably unnecessary, but offers protection against the macro TraceLoggingWideString expanding to something that would invalidate the pointer - return hotkeyStrs.back().c_str(); - }; - - const auto getAdditionalActionHotkeyCStr = [&](const std::wstring& name) - { - const auto it = additionalActionsHotkeys.find(name); - return it != additionalActionsHotkeys.end() ? getHotkeyCStr(it->second) : L""; - }; - - TraceLoggingWriteWrapper( - g_hProvider, - "AdvancedPaste_Settings", - ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), - TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE), - TraceLoggingWideString(getHotkeyCStr(pastePlainHotkey), "PastePlainHotkey"), - TraceLoggingWideString(getHotkeyCStr(advancedPasteUIHotkey), "AdvancedPasteUIHotkey"), - TraceLoggingWideString(getHotkeyCStr(pasteMarkdownHotkey), "PasteMarkdownHotkey"), - TraceLoggingWideString(getHotkeyCStr(pasteJsonHotkey), "PasteJsonHotkey"), - TraceLoggingBoolean(is_advanced_ai_enabled, "IsAdvancedAIEnabled"), - TraceLoggingBoolean(preview_custom_format_output, "ShowCustomPreview"), - TraceLoggingWideString(getAdditionalActionHotkeyCStr(L"ImageToText"), "ImageToTextHotkey"), - TraceLoggingWideString(getAdditionalActionHotkeyCStr(L"PasteAsTxtFile"), "PasteAsTxtFileHotkey"), - TraceLoggingWideString(getAdditionalActionHotkeyCStr(L"PasteAsPngFile"), "PasteAsPngFileHotkey"), - TraceLoggingWideString(getAdditionalActionHotkeyCStr(L"PasteAsHtmlFile"), "PasteAsHtmlFileHotkey"), - TraceLoggingWideString(getAdditionalActionHotkeyCStr(L"TranscodeToMp3"), "TranscodeToMp3Hotkey"), - TraceLoggingWideString(getAdditionalActionHotkeyCStr(L"TranscodeToMp4"), "TranscodeToMp4Hotkey") - ); -} diff --git a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/trace.h b/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/trace.h deleted file mode 100644 index 7ef6250baa..0000000000 --- a/src/modules/AdvancedPaste/AdvancedPasteModuleInterface/trace.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include - -class Trace : public telemetry::TraceBase -{ -public: - // Log if the user has AdvancedPaste enabled or disabled - static void AdvancedPaste_Enable(const bool enabled) noexcept; - - // Log if the user has invoked AdvancedPaste - static void AdvancedPaste_Invoked(std::wstring mode) noexcept; - - // Log if an error occurs in AdvancedPaste - static void Trace::AdvancedPaste_Error(const DWORD errorCode, std::wstring errorMessage, std::wstring methodName) noexcept; - - // Event to send settings telemetry. - static void Trace::AdvancedPaste_SettingsTelemetry(const PowertoyModuleIface::Hotkey& pastePlainHotkey, - const PowertoyModuleIface::Hotkey& advancedPasteUIHotkey, - const PowertoyModuleIface::Hotkey& pasteMarkdownHotkey, - const PowertoyModuleIface::Hotkey& pasteJsonHotkey, - const bool is_advanced_ai_enabled, - const bool preview_custom_format_output, - const std::unordered_map& additionalActionsHotkeys) noexcept; -};